AFNetWorking 深度理解

先看一下afnetworking的目錄結構:

圖1.0

大家都看見了網絡請求其實有兩種方式。一種是用AFHTTPRequestOperationManager ,另一種是用AFHTTPSessionManager捂寿。那么這兩種有什么區(qū)別尼患整?

可能有人有所不知勺择,AFNetworking最初的版本使用的就是AFHTTPRequestOperationManager 以就是自己自定義NSOperation的封裝實現(xiàn)的草雕。AFHTTPSessionManager是在2.0以后才引入進來的。以就是說在2.0之前赃梧,都是使用AFHTTPRequestOperationManager滤蝠。

AFHTTPSessionManager 繼承自 AFURLSessionManager,而AFURLSessionManager主要是使用系統(tǒng)提供的 NSURLSessionNSURLSessionTask進行網絡操作的授嘀。我們看一下官方文檔對這兩個類的描述:

NS_CLASS_AVAILABLE(NSURLSESSION_AVAILABLE, 7_0)
@interface NSURLSession : NSObject

/*
 * NSURLSessionTask - a cancelable object that refers to the lifetime
 * of processing a given request.
 */
NS_CLASS_AVAILABLE(NSURLSESSION_AVAILABLE, 7_0)
@interface NSURLSessionTask : NSObject <NSCopying>

是的物咳,你沒有看錯,NSURLSessionNSURLSessionTaskiOS7以后才出現(xiàn)的蹄皱,所以如果你想要適配到iOS6览闰,那么請你乖乖的使用前者 進行網絡請求芯肤。這就解釋了為什么作者會把兩種請求方式都放在這兒。

下面分兩部分進行網絡AFNetworking網絡請求的分析:
AFHTTPRequestOperationManager 部分的網絡請求原理:

AFHTTPRequestOperationManagerinit方法是這樣的:

- (instancetype)initWithBaseURL:(NSURL *)url {
    self = [super init];
    if (!self) {
        return nil;
    }

    // Ensure terminal slash for baseURL path, so that NSURL +URLWithString:relativeToURL: works as expected
    if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
        url = [url URLByAppendingPathComponent:@""];
    }

    self.baseURL = url;

    self.requestSerializer = [AFHTTPRequestSerializer serializer];
    self.responseSerializer = [AFJSONResponseSerializer serializer];

    self.securityPolicy = [AFSecurityPolicy defaultPolicy];

    self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];

    self.operationQueue = [[NSOperationQueue alloc] init];

    self.shouldUseCredentialStorage = YES;

    return self;
}

其中默認的請求方式和解析方式被設置了默認值:

self.requestSerializer = [AFHTTPRequestSerializer serializer];
self.responseSerializer = [AFJSONResponseSerializer serializer];

當然用戶可以修改這兩個參數(shù)压鉴,指定自己的請求方式和解析方式崖咨。

下面以GET請求為例來說。
當用戶發(fā)起一個GET請求油吭,下面的方法會被掉用:

- (AFHTTPRequestOperation *)GET:(NSString *)URLString
                     parameters:(id)parameters
                        success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
                        failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
    AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithHTTPMethod:@"GET" URLString:URLString parameters:parameters success:success failure:failure];

    [self.operationQueue addOperation:operation];

    return operation;
}

其中[self.operationQueue addOperation:operation];就是將當前的任務放進操作隊列击蹲。
關鍵我們看看AFHTTPRequestOperation 里面都做了什么。

AFHTTPRequestOperation 是繼承自AFURLConnectionOperation婉宰,AFURLConnectionOperation實現(xiàn)了各種代理:

@interface AFURLConnectionOperation : NSOperation <NSURLConnectionDelegate, NSURLConnectionDataDelegate, NSSecureCoding, NSCopying>

我們知道當一個operation任務被啟動的時候start方法就會被調用:

- (void)start {
    [self.lock lock];
    if ([self isCancelled]) {
        [self performSelector:@selector(cancelConnection) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
    } else if ([self isReady]) {
        self.state = AFOperationExecutingState;

        [self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
    }
    [self.lock unlock];
}

- (void)operationDidStart {
    [self.lock lock];
    if (![self isCancelled]) {
        self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO];

        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        for (NSString *runLoopMode in self.runLoopModes) {
            [self.connection scheduleInRunLoop:runLoop forMode:runLoopMode];
            [self.outputStream scheduleInRunLoop:runLoop forMode:runLoopMode];
        }

        [self.outputStream open];
        [self.connection start];
    }
    [self.lock unlock];

    dispatch_async(dispatch_get_main_queue(), ^{
        [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidStartNotification object:self];
    });
}

我們分析一下以上代碼塊歌豺,當AFURLConnectionOperation任務被正常啟動的時候,下面的方法會被調用:

[self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];

operationDidStart方法會在[[self class] networkRequestThread]返回的線程中被調用心包。我們看看這是一個什么樣的線程:
+ (void)networkRequestThreadEntryPoint:(id)__unused object {
    @autoreleasepool {
        [[NSThread currentThread] setName:@"AFNetworking"];

        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
        [runLoop run];
    }
}

+ (NSThread *)networkRequestThread {
    static NSThread *_networkRequestThread = nil;
    static dispatch_once_t oncePredicate;
    dispatch_once(&oncePredicate, ^{
        _networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil];
        [_networkRequestThread start];
    });

    return _networkRequestThread;
}

是的這個新的小線程命名為"AFNetworking", 它在創(chuàng)建的時候就啟動了一個人runloop事件循環(huán)类咧,并添加了一個NSMachPort 空端口,改NSMachPort 僅僅只是一個空的端口其目的是用來維護runloop的執(zhí)行不被退出谴咸。

operationDidStart 方法中的:

        self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO];
        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        for (NSString *runLoopMode in self.runLoopModes) {
            [self.connection scheduleInRunLoop:runLoop forMode:runLoopMode];
            [self.outputStream scheduleInRunLoop:runLoop forMode:runLoopMode];
        }

        [self.outputStream open];
        [self.connection start];

說明self.connectionself.outputStream周期性任務被綁定在當期的runloopself.runLoopModes 模式中轮听。(self.runLoopModes在初始化的時候被賦值為[NSSet setWithObject:NSRunLoopCommonModes]

行了骗露,那么當網絡請求數(shù)據(jù)到達的時候岭佳,數(shù)據(jù)是如何被接收到的尼,我想這一點才是大家最關心的萧锉。
網絡請求是一個異步的過程珊随,當網絡請求數(shù)據(jù)流到達的時候,runloop監(jiān)聽到該事件源__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__方法會被調用柿隙。之后CFNetwork_NSURLConnectionDidReceiveData(_CFURLConnection*, __CFData const*, long, void const*)放會被調用獲取到網絡數(shù)據(jù)叶洞。與此同時NSURLConnectionInternal_withActiveConnectionAndDelegate方法會被調用,本地代理被激活禀崖。AFURLConnectionOperation中的代理方法:

- (void)connection:(NSURLConnection __unused *)connection
    didReceiveData:(NSData *)data
{
    NSUInteger length = [data length];
    while (YES) {
        NSInteger totalNumberOfBytesWritten = 0;
        if ([self.outputStream hasSpaceAvailable]) {
            const uint8_t *dataBuffer = (uint8_t *)[data bytes];

            NSInteger numberOfBytesWritten = 0;
            while (totalNumberOfBytesWritten < (NSInteger)length) {
                numberOfBytesWritten = [self.outputStream write:&dataBuffer[(NSUInteger)totalNumberOfBytesWritten] maxLength:(length - (NSUInteger)totalNumberOfBytesWritten)];
                if (numberOfBytesWritten == -1) {
                    break;
                }

                totalNumberOfBytesWritten += numberOfBytesWritten;
            }

            break;
        } else {
            [self.connection cancel];
            if (self.outputStream.streamError) {
                [self performSelector:@selector(connection:didFailWithError:) withObject:self.connection withObject:self.outputStream.streamError];
            }
            return;
        }
    }

    dispatch_async(dispatch_get_main_queue(), ^{
        self.totalBytesRead += (long long)length;

        if (self.downloadProgress) {
            self.downloadProgress(length, self.totalBytesRead, self.response.expectedContentLength);
        }
    });
}

被調用衩辟,通過以上代碼中的:

           NSInteger numberOfBytesWritten = 0;
            while (totalNumberOfBytesWritten < (NSInteger)length) {
                numberOfBytesWritten = [self.outputStream write:&dataBuffer[(NSUInteger)totalNumberOfBytesWritten] maxLength:(length - (NSUInteger)totalNumberOfBytesWritten)];
                if (numberOfBytesWritten == -1) {
                    break;
                }

                totalNumberOfBytesWritten += numberOfBytesWritten;
            }
            

網絡數(shù)據(jù)流被寫入緩存。數(shù)據(jù)被寫入緩存完成后波附,代理方法:

- (void)connectionDidFinishLoading:(NSURLConnection __unused *)connection {
    self.responseData = [self.outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey];

    [self.outputStream close];
    if (self.responseData) {
       self.outputStream = nil;
    }

    self.connection = nil;

    [self finish];
}

會被調用后艺晴。我們追蹤[self finish]; 看看它里面的實現(xiàn):

- (void)finish {
    [self.lock lock];
    self.state = AFOperationFinishedState;
    [self.lock unlock];

    dispatch_async(dispatch_get_main_queue(), ^{
        [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidFinishNotification object:self];
    });
}

self.state = AFOperationFinishedState這句代碼是重點,它標示了該請求任務已經結束掸屡。而這句賦值還做了一個KVO的操作封寞,如下代碼:

- (void)setState:(AFOperationState)state {
    if (!AFStateTransitionIsValid(self.state, state, [self isCancelled])) {
        return;
    }

    [self.lock lock];
    NSString *oldStateKey = AFKeyPathFromOperationState(self.state);
    NSString *newStateKey = AFKeyPathFromOperationState(state);

    [self willChangeValueForKey:newStateKey];
    [self willChangeValueForKey:oldStateKey];
    _state = state;
    [self didChangeValueForKey:oldStateKey];
    [self didChangeValueForKey:newStateKey];
    [self.lock unlock];
}

NSOperationInternal中的_observeValueForKeyPath:ofObject:changeKind:oldValue:newValue:indexes:context:方法會監(jiān)聽state狀態(tài)的改變。然后回歸到主線程仅财,AFURLConnectionOperation中的setCompletionBlock方法被回調:

- (void)setCompletionBlock:(void (^)(void))block {
    [self.lock lock];
    if (!block) {
        [super setCompletionBlock:nil];
    } else {
        __weak __typeof(self)weakSelf = self;
        [super setCompletionBlock:^ {
            __strong __typeof(weakSelf)strongSelf = weakSelf;

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
            dispatch_group_t group = strongSelf.completionGroup ?: url_request_operation_completion_group();
            dispatch_queue_t queue = strongSelf.completionQueue ?: dispatch_get_main_queue();
#pragma clang diagnostic pop

            dispatch_group_async(group, queue, ^{
                block();
            });

            dispatch_group_notify(group, url_request_operation_completion_queue(), ^{
                [strongSelf setCompletionBlock:nil];
            });
        }];
    }
    [self.lock unlock];
}

關鍵看這句代碼:

dispatch_group_async(group, queue, ^{
                block();
            });

block()一調用就調用到了AFHTTPRequestOperation的方法:

#pragma mark - AFHTTPRequestOperation
- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
                              failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
    // completionBlock is manually nilled out in AFURLConnectionOperation to break the retain cycle.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
#pragma clang diagnostic ignored "-Wgnu"
    self.completionBlock = ^{
        if (self.completionGroup) {
            dispatch_group_enter(self.completionGroup);
        }

        dispatch_async(http_request_operation_processing_queue(), ^{
            if (self.error) {
                if (failure) {
                    dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
                        failure(self, self.error);
                    });
                }
            } else {
                id responseObject = self.responseObject;
                if (self.error) {
                    if (failure) {
                        dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
                            failure(self, self.error);
                        });
                    }
                } else {
                    if (success) {
                        dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
                            success(self, responseObject);
                        });
                    }
                }
            }

            if (self.completionGroup) {
                dispatch_group_leave(self.completionGroup);
            }
        });
    };
#pragma clang diagnostic pop
}

self.completionBlock中的內容被執(zhí)行狈究,這里面最關鍵的一句id responseObject = self.responseObject 獲得了解析數(shù)據(jù),我們看看self.responseObject的實現(xiàn):

- (id)responseObject {
    [self.lock lock];
    if (!_responseObject && [self isFinished] && !self.error) {
        NSError *error = nil;
        self.responseObject = [self.responseSerializer responseObjectForResponse:self.response data:self.responseData error:&error];
        if (error) {
            self.responseSerializationError = error;
        }
    }
    [self.lock unlock];

    return _responseObject;
}

我靠盏求!春天來了抖锥,這句代碼:

self.responseObject = [self.responseSerializer responseObjectForResponse:self.response data:self.responseData error:&error];

stream中的數(shù)據(jù)解析成了我們想要數(shù)據(jù)比如json亿眠、xml、plist等等磅废。然后AFHTTPRequestOperation方法setCompletionBlockWithSuccess中代碼success(self, responseObject)一回調缕探。好了,現(xiàn)在就不用說了还蹲,我們通常就是在這個success block做我們自己的處理的爹耗。

下面我們看一下AFHTTPSessionManager 網絡請求是怎么樣進行的
蘋果已經對NSURLSessionDataTask做了高度的封裝,類似于AFURLConnectionOperation這樣的復雜封裝已經看不見了谜喊。但是原理跟AFURLConnectionOperation的差不多這里就不在贅述了潭兽。

到一個網絡數(shù)據(jù)流到達的時候,NSURLSession的URLSession:dataTask:didReceiveData:方法就會被激活斗遏。AFURLSessionManager實現(xiàn)了NSURLSession的代理山卦,于是乎AFURLSessionManager中的代理方法就會被調用:

- (void)URLSession:(NSURLSession *)session
          dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data
{
    AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask];
    [delegate URLSession:session dataTask:dataTask didReceiveData:data];

    if (self.dataTaskDidReceiveData) {
        self.dataTaskDidReceiveData(session, dataTask, data);
    }
}

[delegate URLSession:session dataTask:dataTask didReceiveData:data]里面的實現(xiàn)四這樣的:

- (void)URLSession:(__unused NSURLSession *)session
          dataTask:(__unused NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data
{
    [self.mutableData appendData:data];
}

這樣網絡數(shù)據(jù)就被寫入了self.mutableData
當數(shù)據(jù)獲取完成之后URLSession:task:didCompleteWithError:方法就會被調用:

- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
    AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];

    // delegate may be nil when completing a task in the background
    if (delegate) {
        [delegate URLSession:session task:task didCompleteWithError:error];

        [self removeDelegateForTask:task];
    }

    if (self.taskDidComplete) {
        self.taskDidComplete(session, task, error);
    }

}

我們看看 [delegate URLSession:session task:task didCompleteWithError:error] 方法中的實現(xiàn):

- (void)URLSession:(__unused NSURLSession *)session
              task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
    __strong AFURLSessionManager *manager = self.manager;

    __block id responseObject = nil;

    __block NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
    userInfo[AFNetworkingTaskDidCompleteResponseSerializerKey] = manager.responseSerializer;

    //Performance Improvement from #2672
    NSData *data = nil;
    if (self.mutableData) {
        data = [self.mutableData copy];
        //We no longer need the reference, so nil it out to gain back some memory.
        self.mutableData = nil;
    }

    if (self.downloadFileURL) {
        userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self.downloadFileURL;
    } else if (data) {
        userInfo[AFNetworkingTaskDidCompleteResponseDataKey] = data;
    }

    if (error) {
        userInfo[AFNetworkingTaskDidCompleteErrorKey] = error;

        dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
            if (self.completionHandler) {
                self.completionHandler(task.response, responseObject, error);
            }

            dispatch_async(dispatch_get_main_queue(), ^{
                [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
            });
        });
    } else {
        dispatch_async(url_session_manager_processing_queue(), ^{
            NSError *serializationError = nil;
            responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError];

            if (self.downloadFileURL) {
                responseObject = self.downloadFileURL;
            }

            if (responseObject) {
                userInfo[AFNetworkingTaskDidCompleteSerializedResponseKey] = responseObject;
            }

            if (serializationError) {
                userInfo[AFNetworkingTaskDidCompleteErrorKey] = serializationError;
            }

            dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
                if (self.completionHandler) {
                    self.completionHandler(task.response, responseObject, serializationError);
                }

                dispatch_async(dispatch_get_main_queue(), ^{
                    [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
                });
            });
        });
    }
#pragma clang diagnostic pop
}

以上代碼中 data = [self.mutableData copy] 可知網絡數(shù)據(jù)流被copy到了 data之中诵次,關鍵代碼:

responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError]
網絡數(shù)據(jù)被解析成了我們最終獲取到的數(shù)據(jù)账蓉。self.completionHandler一執(zhí)行如下代碼塊:

if (self.completionHandler) {
                    self.completionHandler(task.response, responseObject, serializationError);
                }
                

就回到了AFHTTPSessionManager的方法:

- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
                                       URLString:(NSString *)URLString
                                      parameters:(id)parameters
                                         success:(void (^)(NSURLSessionDataTask *, id))success
                                         failure:(void (^)(NSURLSessionDataTask *, NSError *))failure
{
    NSError *serializationError = nil;
    NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
    if (serializationError) {
        if (failure) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
            dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
                failure(nil, serializationError);
            });
#pragma clang diagnostic pop
        }

        return nil;
    }

    __block NSURLSessionDataTask *dataTask = nil;
    dataTask = [self dataTaskWithRequest:request completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
        if (error) {
            if (failure) {
                failure(dataTask, error);
            }
        } else {
            if (success) {
                success(dataTask, responseObject);
            }
        }
    }];

    return dataTask;
}

block就會被調用:

    __block NSURLSessionDataTask *dataTask = nil;
    dataTask = [self dataTaskWithRequest:request completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
        if (error) {
            if (failure) {
                failure(dataTask, error);
            }
        } else {
            if (success) {
                success(dataTask, responseObject);
            }
        }
    }];

這里的successfailure 就是我們經常看見的回調方法逾一。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末铸本,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子遵堵,更是在濱河造成了極大的恐慌箱玷,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件陌宿,死亡現(xiàn)場離奇詭異锡足,居然都是意外死亡,警方通過查閱死者的電腦和手機壳坪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門舶得,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人爽蝴,你說我怎么就攤上這事沐批。” “怎么了霜瘪?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵珠插,是天一觀的道長。 經常有香客問我颖对,道長捻撑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮顾患,結果婚禮上番捂,老公的妹妹穿的比我還像新娘。我一直安慰自己江解,他們只是感情好设预,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著犁河,像睡著了一般鳖枕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上桨螺,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天宾符,我揣著相機與錄音,去河邊找鬼灭翔。 笑死魏烫,一個胖子當著我的面吹牛,可吹牛的內容都是我干的肝箱。 我是一名探鬼主播哄褒,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼煌张!你這毒婦竟也來了呐赡?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤唱矛,失蹤者是張志新(化名)和其女友劉穎罚舱,沒想到半個月后井辜,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绎谦,經...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年粥脚,在試婚紗的時候發(fā)現(xiàn)自己被綠了窃肠。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡刷允,死狀恐怖冤留,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情树灶,我是刑警寧澤纤怒,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站天通,受9級特大地震影響泊窘,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一烘豹、第九天 我趴在偏房一處隱蔽的房頂上張望瓜贾。 院中可真熱鬧,春花似錦携悯、人聲如沸祭芦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽龟劲。三九已至,卻和暖如春轴或,著一層夾襖步出監(jiān)牢的瞬間咸灿,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工侮叮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留避矢,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓囊榜,卻偏偏與公主長得像审胸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子卸勺,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內容