AFNetworking源碼探究(三) —— GET請(qǐng)求實(shí)現(xiàn)之任務(wù)進(jìn)度設(shè)置和通知監(jiān)聽(一)

版本記錄

版本號(hào) 時(shí)間
V1.0 2018.02.28

前言

我們做APP發(fā)起網(wǎng)絡(luò)請(qǐng)求崭别,都離不開一個(gè)非常有用的框架AFNetworking政溃,可以說這個(gè)框架的知名度已經(jīng)超過了蘋果的底層網(wǎng)絡(luò)請(qǐng)求部分,很多人可能不知道蘋果底層是如何發(fā)起網(wǎng)絡(luò)請(qǐng)求的,但是一定知道AFNetworking,接下來幾篇我們就一起詳細(xì)的解析一下這個(gè)框架夯巷。感興趣的可以看上面寫的幾篇。
1. AFNetworking源碼探究(一) —— 基本介紹
2. AFNetworking源碼探究(二) —— GET請(qǐng)求實(shí)現(xiàn)之NSURLSessionDataTask實(shí)例化(一)

回顧

上一篇從GET請(qǐng)求入口開始哀墓,進(jìn)行深入分析趁餐,包括實(shí)例化NSURLSessionDataTask的過程以及為任務(wù)添加代理和通知觀察。本篇會(huì)看一下代理和進(jìn)度之間的關(guān)系以及通知的作用篮绰。


AFURLSessionManagerTaskDelegate代理為任務(wù)設(shè)置進(jìn)度

主要對(duì)應(yīng)的就是下面這一段代碼

- (void)setupProgressForTask:(NSURLSessionTask *)task {
    __weak __typeof__(task) weakTask = task;

    self.uploadProgress.totalUnitCount = task.countOfBytesExpectedToSend;
    self.downloadProgress.totalUnitCount = task.countOfBytesExpectedToReceive;
    [self.uploadProgress setCancellable:YES];
    [self.uploadProgress setCancellationHandler:^{
        __typeof__(weakTask) strongTask = weakTask;
        [strongTask cancel];
    }];
    [self.uploadProgress setPausable:YES];
    [self.uploadProgress setPausingHandler:^{
        __typeof__(weakTask) strongTask = weakTask;
        [strongTask suspend];
    }];
    if ([self.uploadProgress respondsToSelector:@selector(setResumingHandler:)]) {
        [self.uploadProgress setResumingHandler:^{
            __typeof__(weakTask) strongTask = weakTask;
            [strongTask resume];
        }];
    }

    [self.downloadProgress setCancellable:YES];
    [self.downloadProgress setCancellationHandler:^{
        __typeof__(weakTask) strongTask = weakTask;
        [strongTask cancel];
    }];
    [self.downloadProgress setPausable:YES];
    [self.downloadProgress setPausingHandler:^{
        __typeof__(weakTask) strongTask = weakTask;
        [strongTask suspend];
    }];

    if ([self.downloadProgress respondsToSelector:@selector(setResumingHandler:)]) {
        [self.downloadProgress setResumingHandler:^{
            __typeof__(weakTask) strongTask = weakTask;
            [strongTask resume];
        }];
    }

    [task addObserver:self
           forKeyPath:NSStringFromSelector(@selector(countOfBytesReceived))
              options:NSKeyValueObservingOptionNew
              context:NULL];
    [task addObserver:self
           forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToReceive))
              options:NSKeyValueObservingOptionNew
              context:NULL];

    [task addObserver:self
           forKeyPath:NSStringFromSelector(@selector(countOfBytesSent))
              options:NSKeyValueObservingOptionNew
              context:NULL];
    [task addObserver:self
           forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToSend))
              options:NSKeyValueObservingOptionNew
              context:NULL];

    [self.downloadProgress addObserver:self
                            forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
                               options:NSKeyValueObservingOptionNew
                               context:NULL];
    [self.uploadProgress addObserver:self
                          forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
                             options:NSKeyValueObservingOptionNew
                             context:NULL];
}

下面我們就一起看一下這個(gè)是怎么實(shí)現(xiàn)的后雷。

1. 上傳進(jìn)度

關(guān)于上傳進(jìn)度,這里涉及到取消吠各、暫停以及重新開始的回調(diào)和處理臀突。

self.uploadProgress.totalUnitCount = task.countOfBytesExpectedToSend;
self.downloadProgress.totalUnitCount = task.countOfBytesExpectedToReceive;
[self.uploadProgress setCancellable:YES];
[self.uploadProgress setCancellationHandler:^{
    __typeof__(weakTask) strongTask = weakTask;
    [strongTask cancel];
}];
[self.uploadProgress setPausable:YES];
[self.uploadProgress setPausingHandler:^{
    __typeof__(weakTask) strongTask = weakTask;
    [strongTask suspend];
}];
if ([self.uploadProgress respondsToSelector:@selector(setResumingHandler:)]) {
    [self.uploadProgress setResumingHandler:^{
        __typeof__(weakTask) strongTask = weakTask;
        [strongTask resume];
    }];
}

首先就是獲取上傳和下載的總長度,用的就是NSURLSession的屬性走孽。

self.uploadProgress.totalUnitCount = task.countOfBytesExpectedToSend;
self.downloadProgress.totalUnitCount = task.countOfBytesExpectedToReceive;

/* number of body bytes we expect to send, derived from the Content-Length of the HTTP request */
@property (readonly) int64_t countOfBytesExpectedToSend;

/* number of byte bytes we expect to receive, usually derived from the Content-Length header of an HTTP response. */
@property (readonly) int64_t countOfBytesExpectedToReceive;

這個(gè)總的字節(jié)數(shù)惧辈,都可以從HTTP頭中獲取。這里還算很清晰了磕瓷,下面簡單的介紹和說明盒齿。

(a) 取消

主要就是下面幾句代碼

[self.uploadProgress setCancellable:YES];
[self.uploadProgress setCancellationHandler:^{
    __typeof__(weakTask) strongTask = weakTask;
    [strongTask cancel];
}];

首先要設(shè)置的就是可取消cancallable這個(gè)屬性,需要設(shè)置為YES困食。

/* Whether the work being done can be cancelled or paused, respectively. 
By default NSProgresses are cancellable but not pausable. NSProgress is by default 
KVO-compliant for these properties, with the notifications always being sent on the thread which updates the property. 
These properties are for communicating whether controls for cancelling and pausing should appear in a progress reporting user interface. 
NSProgress itself does not do anything with these properties other than help pass their values from progress reporters to progress observers. 
It is valid for the values of these properties to change in virtually any way during the lifetime of an NSProgress. 
Of course, if an NSProgress is cancellable you should actually implement cancellability by setting a cancellation handler or by making your code poll the result of invoking -isCancelled. 
Likewise for pausability.
*/
@property (getter=isCancellable) BOOL cancellable;

所做的工作是否可以分別取消或暫停边翁。 默認(rèn)情況下,NSProgresses是可取消的硕盹,但不可pausable符匾。 對(duì)于這些屬性,NSProgress默認(rèn)為符合KVO標(biāo)準(zhǔn)瘩例,并且通知始終在更新屬性的線程上發(fā)送啊胶。 這些屬性用于傳遞是否應(yīng)該在進(jìn)度報(bào)告用戶界面中顯示取消和暫停的控件。 NSProgress本身不會(huì)對(duì)這些屬性做任何事情垛贤,除了幫助將進(jìn)度記錄的值傳遞給進(jìn)度觀察員焰坪。 在NSProgress的生命周期中,這些屬性的值實(shí)際上以任何方式改變都是有效的聘惦。 當(dāng)然某饰,如果一個(gè)NSProgress可以被取消,你應(yīng)該通過設(shè)置一個(gè)取消處理程序或者讓你的代碼輪詢調(diào)用-isCancelled的結(jié)果來實(shí)現(xiàn)可取消性。 同樣適用于pausability黔漂。

然后就是在cancelHander中進(jìn)行取消業(yè)務(wù)的處理。

[self.uploadProgress setCancellationHandler:^{
    __typeof__(weakTask) strongTask = weakTask;
    [strongTask cancel];
}];

這里就是直接調(diào)用任務(wù)Task的取消操作[strongTask cancel]劳较。

/* -cancel returns immediately, but marks a task as being canceled.
 * The task will signal -URLSession:task:didCompleteWithError: with an
 * error value of { NSURLErrorDomain, NSURLErrorCancelled }.  In some 
 * cases, the task may signal other work before it acknowledges the 
 * cancelation.  -cancel may be sent to a task that has been suspended.
 */
- (void)cancel;

- cancel立即返回墓捻,但將任務(wù)標(biāo)記為被取消。 該任務(wù)將發(fā)信號(hào)-URLSession:task:didCompleteWithError:錯(cuò)誤值為{NSURLErrorDomain,NSURLErrorCancelled}。 在某些情況下颜骤,任務(wù)可能在確認(rèn)取消之前發(fā)出其他工作的信號(hào)。- cancel可能被發(fā)送到已被暫停的任務(wù)锈锤。

(b) 暫停

主要就是對(duì)應(yīng)下面幾句代碼

[self.uploadProgress setPausable:YES];
[self.uploadProgress setPausingHandler:^{
    __typeof__(weakTask) strongTask = weakTask;
    [strongTask suspend];
}];

我們看一下[strongTask suspend]

/*
 * Suspending a task will prevent the NSURLSession from continuing to
 * load data.  There may still be delegate calls made on behalf of
 * this task (for instance, to report data received while suspending)
 * but no further transmissions will be made on behalf of the task
 * until -resume is sent.  The timeout timer associated with the task
 * will be disabled while a task is suspended. -suspend and -resume are
 * nestable. 
 */
- (void)suspend;
- (void)resume;

暫停任務(wù)將阻止NSURLSession繼續(xù)加載數(shù)據(jù)记舆。 可能仍然存在代表此任務(wù)的代理在調(diào)用(例如衣赶,報(bào)告掛起時(shí)收到的數(shù)據(jù))遵馆,但不會(huì)有代表任務(wù)進(jìn)行進(jìn)一步的傳輸直到發(fā)送- resume换况。 與任務(wù)關(guān)聯(lián)的超時(shí)定時(shí)器將在任務(wù)暫停時(shí)被禁用复隆。 - ususpend- resume是可嵌套的拨匆。

(c) 開始

主要就是對(duì)應(yīng)下面這段代碼

if ([self.uploadProgress respondsToSelector:@selector(setResumingHandler:)]) {
    [self.uploadProgress setResumingHandler:^{
        __typeof__(weakTask) strongTask = weakTask;
        [strongTask resume];
    }];
}

這里說一下這個(gè)resumingHandler,開始進(jìn)行任務(wù)的處理

/* A block to be invoked when resume is invoked. 
The block will be invoked even when the method is invoked on an ancestor of the receiver, 
or an instance of NSProgress in another process that resulted from publishing the receiver or an ancestor of the receiver. 
Your block won't be invoked on any particular queue. 
If it must do work on a specific queue then it should schedule that work on that queue.
 */
@property (nullable, copy) void (^resumingHandler)(void) NS_AVAILABLE(10_11, 9_0);

調(diào)用resume時(shí)要調(diào)用的塊挽拂。 即使該方法在接收方的super類上調(diào)用惭每,或者由于發(fā)布接收方或接收方的super類而導(dǎo)致的另一個(gè)進(jìn)程中的NSProgress實(shí)例,也會(huì)調(diào)用該block亏栈。 您的塊不會(huì)在任何特定隊(duì)列上調(diào)用台腥。 如果它必須在特定的隊(duì)列上工作,那么它應(yīng)該在該隊(duì)列上安排該工作绒北。

2. 下載進(jìn)度

首先看一下這部分的代碼

[self.downloadProgress setCancellable:YES];
[self.downloadProgress setCancellationHandler:^{
    __typeof__(weakTask) strongTask = weakTask;
    [strongTask cancel];
}];
[self.downloadProgress setPausable:YES];
[self.downloadProgress setPausingHandler:^{
    __typeof__(weakTask) strongTask = weakTask;
    [strongTask suspend];
}];

if ([self.downloadProgress respondsToSelector:@selector(setResumingHandler:)]) {
    [self.downloadProgress setResumingHandler:^{
        __typeof__(weakTask) strongTask = weakTask;
        [strongTask resume];
    }];
}

和上傳一樣黎侈,包括取消,暫停和開始闷游,下面我們就一起看一下峻汉。

(a) 取消

主要對(duì)應(yīng)下面幾句代碼

[self.downloadProgress setCancellable:YES];
[self.downloadProgress setCancellationHandler:^{
    __typeof__(weakTask) strongTask = weakTask;
    [strongTask cancel];
}];

這個(gè)不多說了贴汪,對(duì)比上傳的取消。

(b) 暫停

主要對(duì)應(yīng)下面幾句代碼

[self.downloadProgress setPausable:YES];
[self.downloadProgress setPausingHandler:^{
    __typeof__(weakTask) strongTask = weakTask;
    [strongTask suspend];
}];

這個(gè)不多說了休吠,對(duì)比上傳的暫停扳埂。

(c) 開始

主要對(duì)應(yīng)下面這幾句代碼

if ([self.downloadProgress respondsToSelector:@selector(setResumingHandler:)]) {
    [self.downloadProgress setResumingHandler:^{
        __typeof__(weakTask) strongTask = weakTask;
        [strongTask resume];
    }];
}

這個(gè)不多說了,對(duì)比上傳的開始瘤礁。

3. 給Task和上傳下載進(jìn)度增加KVO觀察

主要對(duì)應(yīng)下面這幾句代碼

[task addObserver:self
       forKeyPath:NSStringFromSelector(@selector(countOfBytesReceived))
          options:NSKeyValueObservingOptionNew
          context:NULL];
[task addObserver:self
       forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToReceive))
          options:NSKeyValueObservingOptionNew
          context:NULL];

[task addObserver:self
       forKeyPath:NSStringFromSelector(@selector(countOfBytesSent))
          options:NSKeyValueObservingOptionNew
          context:NULL];
[task addObserver:self
       forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToSend))
          options:NSKeyValueObservingOptionNew
          context:NULL];

[self.downloadProgress addObserver:self
                        forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
                           options:NSKeyValueObservingOptionNew
                           context:NULL];
[self.uploadProgress addObserver:self
                      forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
                         options:NSKeyValueObservingOptionNew
                         context:NULL];

都是self阳懂,也就是AFURLSessionManager,來觀察NSURLSessionTask的四個(gè)屬性countOfBytesReceived柜思、countOfBytesSent岩调、countOfBytesExpectedToSend、countOfBytesExpectedToReceive以及進(jìn)度的fractionCompleted屬性赡盘。

/* Byte count properties may be zero if no body is expected, 
 * or NSURLSessionTransferSizeUnknown if it is not possible 
 * to know how many bytes will be transferred.
 */

/* number of body bytes already received */
@property (readonly) int64_t countOfBytesReceived;

/* number of body bytes already sent */
@property (readonly) int64_t countOfBytesSent;

/* number of body bytes we expect to send, derived from the Content-Length of the HTTP request */
@property (readonly) int64_t countOfBytesExpectedToSend;

/* number of byte bytes we expect to receive, usually derived from the Content-Length header of an HTTP response. */
@property (readonly) int64_t countOfBytesExpectedToReceive;
/* The fraction of the overall work completed by this progress object, including work done by any children it may have.
*/
@property (readonly) double fractionCompleted;

此進(jìn)度對(duì)象完成的全部工作的一小部分号枕,包括可能有的任何子節(jié)點(diǎn)所做的工作。

下面我們就一起看一下KVO的監(jiān)聽部分亡脑。

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    if ([object isKindOfClass:[NSURLSessionTask class]] || [object isKindOfClass:[NSURLSessionDownloadTask class]]) {
        if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesReceived))]) {
            self.downloadProgress.completedUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
        } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesExpectedToReceive))]) {
            self.downloadProgress.totalUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
        } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesSent))]) {
            self.uploadProgress.completedUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
        } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesExpectedToSend))]) {
            self.uploadProgress.totalUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
        }
    }
    else if ([object isEqual:self.downloadProgress]) {
        if (self.downloadProgressBlock) {
            self.downloadProgressBlock(object);
        }
    }
    else if ([object isEqual:self.uploadProgress]) {
        if (self.uploadProgressBlock) {
            self.uploadProgressBlock(object);
        }
    }
}

這里堕澄,首先判斷object的類型,如果是NSURLSessionTask或者NSURLSessionDownloadTask霉咨,然后判斷的是keyPath蛙紫,如果是對(duì)應(yīng)屬性或者鍵路徑,那么就更新downloadProgress或者uploadProgress的幾個(gè)對(duì)應(yīng)屬性的值途戒。

如果object是downloadProgress坑傅,那么就調(diào)用block AFURLSessionTaskProgressBlock

@property (nonatomic, copy) AFURLSessionTaskProgressBlock downloadProgressBlock;
typedef void (^AFURLSessionTaskProgressBlock)(NSProgress *);

else if ([object isEqual:self.downloadProgress]) {
    if (self.downloadProgressBlock) {
        self.downloadProgressBlock(object);
    }
}

如果object是uploadProgress喷斋,那么就調(diào)用block AFURLSessionTaskProgressBlock唁毒。

@property (nonatomic, copy) AFURLSessionTaskProgressBlock uploadProgressBlock;
typedef void (^AFURLSessionTaskProgressBlock)(NSProgress *);

else if ([object isEqual:self.uploadProgress]) {
    if (self.uploadProgressBlock) {
        self.uploadProgressBlock(object);
    }
}

大家可以看到,這上傳和下載的block都是同一個(gè)類型的block星爪,它們是不同的實(shí)例對(duì)象而已浆西。


AFURLSessionManager為任務(wù)添加通知監(jiān)聽

上一篇講述過,添加通知監(jiān)聽如下:

[self addNotificationObserverForTask:task];

- (void)addNotificationObserverForTask:(NSURLSessionTask *)task {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidResume:) name:AFNSURLSessionTaskDidResumeNotification object:task];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidSuspend:) name:AFNSURLSessionTaskDidSuspendNotification object:task];
}

1. 開始

- (NSString *)taskDescriptionForSessionTasks {
    return [NSString stringWithFormat:@"%p", self];
}
- (void)taskDidResume:(NSNotification *)notification {
    NSURLSessionTask *task = notification.object;
    if ([task respondsToSelector:@selector(taskDescription)]) {
        if ([task.taskDescription isEqualToString:self.taskDescriptionForSessionTasks]) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidResumeNotification object:task];
            });
        }
    }
}

一起來看一下這里的邏輯顽腾,首先就是取出任務(wù)notification.object近零,然后判斷[task.taskDescription isEqualToString:self.taskDescriptionForSessionTasks],這里self.taskDescriptionForSessionTasks的意思就是當(dāng)前實(shí)例化對(duì)象的地址抄肖。判斷如果是YES久信,那么就在主線程發(fā)送通知。

//通知名字

NSString * const AFNetworkingTaskDidResumeNotification = @"com.alamofire.networking.task.resume";

2. 暫停

- (void)taskDidSuspend:(NSNotification *)notification {
    NSURLSessionTask *task = notification.object;
    if ([task respondsToSelector:@selector(taskDescription)]) {
        if ([task.taskDescription isEqualToString:self.taskDescriptionForSessionTasks]) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidSuspendNotification object:task];
            });
        }
    }
}

暫停的邏輯參考開始漓摩,不同的地方就在于發(fā)送通知的name不一樣而已裙士。

NSString * const AFNetworkingTaskDidSuspendNotification = @"com.alamofire.networking.task.suspend";

具體,這兩個(gè)通知有什么用管毙,誰監(jiān)聽做什么腿椎,后面會(huì)和大家進(jìn)行說明桌硫。

后記

本篇主要講述的就是lock之內(nèi)所做的事情,主要包括AFURLSessionManagerTaskDelegate代理為任務(wù)設(shè)置進(jìn)度和AFURLSessionManager為任務(wù)添加通知監(jiān)聽酥诽。后面會(huì)繼續(xù)鞍泉,喜歡的給個(gè)關(guān)注~~~。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末肮帐,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子边器,更是在濱河造成了極大的恐慌训枢,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件忘巧,死亡現(xiàn)場離奇詭異恒界,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)砚嘴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門十酣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人际长,你說我怎么就攤上這事耸采。” “怎么了工育?”我有些...
    開封第一講書人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵虾宇,是天一觀的道長。 經(jīng)常有香客問我如绸,道長嘱朽,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任怔接,我火速辦了婚禮搪泳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘扼脐。我一直安慰自己岸军,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開白布谎势。 她就那樣靜靜地躺著凛膏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪脏榆。 梳的紋絲不亂的頭發(fā)上猖毫,一...
    開封第一講書人閱讀 49,929評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音须喂,去河邊找鬼吁断。 笑死趁蕊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的仔役。 我是一名探鬼主播掷伙,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼又兵!你這毒婦竟也來了任柜?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤沛厨,失蹤者是張志新(化名)和其女友劉穎宙地,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體逆皮,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡宅粥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了电谣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片秽梅。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖剿牺,靈堂內(nèi)的尸體忽然破棺而出企垦,到底是詐尸還是另有隱情,我是刑警寧澤牢贸,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布竹观,位于F島的核電站,受9級(jí)特大地震影響潜索,放射性物質(zhì)發(fā)生泄漏臭增。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一竹习、第九天 我趴在偏房一處隱蔽的房頂上張望誊抛。 院中可真熱鬧,春花似錦整陌、人聲如沸拗窃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽随夸。三九已至,卻和暖如春震放,著一層夾襖步出監(jiān)牢的瞬間宾毒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來泰國打工殿遂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留诈铛,地道東北人乙各。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像幢竹,于是被迫代替她去往敵國和親耳峦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容