PromiseKit源碼分析

廢話不多說(shuō),本博就開(kāi)工仿便。

源碼地址
本博客沒(méi)有關(guān)注swift 谦去,因此還是采用oc方式分析源碼,源碼來(lái)自pod 更新

pod 'PromiseKit', '~> 1.0'

概述

promise 是用來(lái)處理回調(diào)地獄的,借鑒圖


image

基本使用

本文看alert 的promise

    UIAlertView * alertview=[[UIAlertView alloc]initWithTitle:@"alert" message:@"promiseTest" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"確定", nil];
    [alertview promise].then(^{
        NSLog(@"dddd");
    });

結(jié)果呢


image.png

這是怎么實(shí)現(xiàn)的呢外傅?進(jìn)入正題纪吮。


promise 源碼實(shí)現(xiàn)

引出核心代碼

@interface PMKAlertViewDelegater : NSObject <UIAlertViewDelegate> {
@public
    void (^fulfiller)(id);
}
@end


@implementation PMKAlertViewDelegater

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
    fulfiller(PMKManifold(@(buttonIndex), alertView));
    PMKRelease(self);
}

@end

@implementation UIAlertView (PromiseKit)

- (PMKPromise *)promise {
    PMKAlertViewDelegater *d = [PMKAlertViewDelegater new];
    PMKRetain(d);
    self.delegate = d;
    [self show];
    return [PMKPromise new:^(id fulfiller, id rejecter){
        d->fulfiller = fulfiller;
    }];
}

@end

從上面我們UIAlertView Category 中我們能看出來(lái),這里調(diào)用- (PMKPromise *)promise

1.我們會(huì)創(chuàng)建UIAlertView的一個(gè)代理并且Retain

  1. 將對(duì)象設(shè)置為UIAlertView 的代理
    3.展示Alert
    4.生成一個(gè)promise

這里重點(diǎn)是第四步生成promise萎胰。

這里我們可以看看其他零散的小知識(shí)點(diǎn)宏定義

extern void *PMKManualReferenceAssociatedObject;
#define PMKRetain(obj)  objc_setAssociatedObject(obj, PMKManualReferenceAssociatedObject, obj, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
#define PMKRelease(obj) objc_setAssociatedObject(obj, PMKManualReferenceAssociatedObject, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC)

這里PMKRetain 都是采用關(guān)聯(lián)引用進(jìn)行保存對(duì)象
PMKRelease 采用關(guān)聯(lián)引用對(duì)對(duì)象近視釋放 碾盟,成對(duì)出現(xiàn)的。

這里還有個(gè)限制參數(shù)的宏定義技竟,編譯階段就知道了參數(shù)的個(gè)數(shù)

#define PMKManifold(...) __PMKManifold(__VA_ARGS__, 3, 2, 1)
#define __PMKManifold(_1, _2, _3, N, ...) __PMKArrayWithCount(N, _1, _2, _3)
extern id __PMKArrayWithCount(NSUInteger, ...);

這里 ... 就是用VA_ARGS 代表的冰肴,代表無(wú)限參數(shù)
怎么看這個(gè)宏定義呢?我們就是把參數(shù)帶人一步步看就知道了

假設(shè)我們的參數(shù)是@1 榔组,@2熙尉,@3 這個(gè)宏定義運(yùn)行的結(jié)果是 __PMKArrayWithCount(3, @1, @2, @3);可以幫助我們自動(dòng)獲取參數(shù)的個(gè)數(shù),不過(guò)這里最多只支持三個(gè)
1 PMKManifold(@1 搓扯,@2检痰,@3) 轉(zhuǎn)換成__PMKManifold(@1 ,@2锨推,@3,3,2,1) VA_ARGS 換成 @1 铅歼,@2公壤,@3*
__PMKManifold(@1 ,@2谭贪,@3,3,2,1) 轉(zhuǎn)換成 __PMKArrayWithCount(3, @1 境钟,@2,@3) 這里N 是3

這是宏定義的二次處理俭识。編譯階段我們就知道參數(shù)的個(gè)數(shù)了慨削。性能能改善一點(diǎn)是一點(diǎn)吧。

核心源碼類PMKPromise

PMKPromise 類結(jié)構(gòu)

這個(gè)類結(jié)構(gòu)比較簡(jiǎn)單


PMKPromise.png
PMKPromise 類初始化

看了API 作者沒(méi)有標(biāo)記那個(gè)是真正的初始化API
真正生成對(duì)象的API是

+ (instancetype)promiseWithResolver:(void (^)(PMKResolver))block 

默認(rèn)的+init 方法給重寫設(shè)置無(wú)效

typedef void (^PMKResolver)(id);

+ (instancetype)promiseWithResolver:(void (^)(PMKResolver))block {
    PMKPromise *this = [self alloc];
    this->_promiseQueue = PMKCreatePromiseQueue();
    this->_handlers = [NSMutableArray new];

    @try {
        block(^(id result){
            if (PMKGetResult(this))
                return PMKLog(@"PromiseKit: Warning: Promise already resolved");

            PMKResolve(this, result);
        });
    } @catch (id e) {
        // at this point, no pointer to the Promise has been provided
        // to the user, so we can’t have any handlers, so all we need
        // to do is set _result. Technically using PMKSetResult is
        // not needed either, but this seems better safe than sorry.
        PMKSetResult(this, NSErrorFromException(e));
    }

    return this;
}

這里我們看傳入的參數(shù)只有一個(gè)PMKResolver類型的block

1 入?yún)ⅲ?傳入PMKResolver 類型block
2 初始化: 創(chuàng)建PMKPromise 對(duì)象套媚,分配空間
3 給PMKPromise 對(duì)象 的成員變量_promiseQueue設(shè)置值缚态。queue 是一個(gè)DISPATCH_QUEUE_CONCURRENT 類型的queue 。(Concurrent Dispatch Queue不過(guò)創(chuàng)建多少都沒(méi)有問(wèn)題堤瘤,因?yàn)镃oncurrent Dispatch Queue所使用的線程由系統(tǒng)的XNU內(nèi)核高效管理玫芦,不會(huì)影響系統(tǒng)性能。
這里上個(gè)圖

image.png

4創(chuàng)建 數(shù)組給 _handlers 賦值
5 try catch 調(diào)用 PMKResolver 類型的block 本辐。傳入的參數(shù)是block 桥帆,類型是^(id result){}。 調(diào)用block 失敗了慎皱,調(diào)用**static NSArray PMKSetResult(PMKPromise this, id result)老虫。
6 返回this

這里看完好多人肯定一頭霧水,這是在干么茫多。其實(shí)把祈匙,這里是我們只是創(chuàng)建了個(gè)PMKPromise ,我們采用了block的保存語(yǔ)句塊的功能天揖,將對(duì)這個(gè)PMKPromise 對(duì)象的處理放在了外面夺欲。如果外界需要對(duì)我處理,那么調(diào)用我給你外界的句柄 block今膊。(這里要是傳入的參數(shù)不對(duì)些阅,那么我就直接對(duì)這個(gè)PMKPromise 做錯(cuò)誤處理)

結(jié)構(gòu)如下


image.png

我們先看看要是外界傳入的參數(shù)block 不合法,我們調(diào)用的static NSArray *PMKSetResult(PMKPromise *this, id result)

static NSArray *PMKSetResult(PMKPromise *this, id result) {
    __block NSArray *handlers;
    result = PMKSanitizeResult(result);
    dispatch_barrier_sync(this->_promiseQueue, ^{
        handlers = this->_handlers;
        this->_result = result;
        this->_handlers = nil;
    });

    return handlers;
}

1 調(diào)用PMKSanitizeResult對(duì)結(jié)果進(jìn)行處理下斑唬,保證結(jié)果不是nil市埋。
2 在promise queue中獲取下handle ,將handle處理為nil 赖钞,將成員變量_result 賦值(一定不是nil腰素,nil代表這個(gè)promise還沒(méi)有被處理,是promise的一種狀態(tài))
3 返回handles

這里沒(méi)有對(duì)返回的handle 做處理

我們看看如何處理PMKPromise雪营,外界調(diào)用這個(gè)block發(fā)生了什么事情

^(id result){
            if (PMKGetResult(this))
                return PMKLog(@"PromiseKit: Warning: Promise already resolved");

            PMKResolve(this, result);
        }

1.這里很簡(jiǎn)單弓千, 調(diào)用static id PMKGetResult(PMKPromise this) 判斷 PMKPromise 是否有結(jié)果,有結(jié)果就返回献起。(具體怎么返回看下面)
2 如果
* PMKPromise** 沒(méi)有設(shè)置結(jié)果就調(diào)用*static void PMKResolve(PMKPromise this, id result) 將結(jié)果設(shè)置到PMKPromise 的變量_result 中(具體函數(shù)分析往下面看)

先看*static id PMKGetResult(PMKPromise this)

static id PMKGetResult(PMKPromise *this) {
    __block id result;
    dispatch_sync(this->_promiseQueue, ^{
        result = this->_result;
    });
    return result;
}

這個(gè)很簡(jiǎn)單洋访,就是獲取下PMKPromise 的成員變量 _result的值.不過(guò)是同步獲取镣陕,意思是當(dāng)前線程中獲取下 結(jié)果返回。

再看下*static void PMKResolve(PMKPromise this, id result)

static void PMKResolve(PMKPromise *this, id result) {
    void (^set)(id) = ^(id r){
        NSArray *handlers = PMKSetResult(this, r);
        for (void (^handler)(id) in handlers)
            handler(r);
    };

    if (IsPromise(result)) {
        PMKPromise *next = result;
        dispatch_barrier_sync(next->_promiseQueue, ^{
            id nextResult = next->_result;
            
            if (nextResult == nil) {  // ie. pending
                [next->_handlers addObject:^(id o){
                    PMKResolve(this, o);
                }];
            } else
                set(nextResult);
        });
    } else
        set(result);
}

這算是對(duì)PMKPromise 處理的核心函數(shù)了

1 聲明一個(gè) block 命名set 姻政。調(diào)用這個(gè)set block 呆抑。這個(gè)block中會(huì)先調(diào)用PMKSetResult,對(duì)這個(gè)promise 進(jìn)行賦值操作汁展,然后在處理所有的handle鹊碍。(這里根據(jù)handle的調(diào)用和下文知道也是一個(gè)block
2 這里是個(gè)宏定義判斷result 是不是promise
3 result 不是 promise 那么就調(diào)用set block
4 result 是promise,命名為next 食绿,那么獲取next這個(gè)promise 的 成員變量_result侈咕。要是這個(gè)promise 還沒(méi)有設(shè)置結(jié)果,那么我們next的_handle 成員變量中要保存一個(gè)block器紧,這個(gè)block是處理this promise的句柄(意思是next 調(diào)用set的時(shí)候耀销,需要將result 告訴下this)。要是promise 的設(shè)置了結(jié)果铲汪,那么就調(diào)用set block

看到這里我估計(jì)好多人只是看懂了函數(shù)本身熊尉,但是整體沒(méi)有看懂。因此在做個(gè)整體圖明晰下


image.png

這里舉例說(shuō)明

類的成員變量
{
        void (^fulfiller)(id);
        PMKPromise * promiseNext;
    PMKPromise * promiseThis;
}

 promiseThis = [PMKPromise new:^(PMKFulfiller fulfill, PMKRejecter reject) {
        fulfill(promiseNext);
    }];
    
    UIAlertView * alertview=[[UIAlertView alloc]initWithTitle:@"alert" message:@"promiseTest" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"確定", nil];
    [alertview promise].then(^{
       fulfiller(@"nextPromise");
        NSLog(@"%@",promiseThis.value);
    });

這里就知道了掌腰。handle 中保存的是所有的其他的依賴結(jié)果的promise狰住。不單單是一個(gè)「ㄕ澹可以是多個(gè)转晰。

這里我們?cè)倏纯碪IAlertView 調(diào)用的這個(gè)初始化方法

+ (instancetype)new:(void(^)(PMKFulfiller, PMKRejecter))block {
    return [self promiseWithResolver:^(PMKResolver resolve) {
        id rejecter = ^(id error){
            if (error == nil) {
                error = NSErrorFromNil();
            } else if (IsPromise(error) && [error rejected]) {
                // this is safe, acceptable and (basically) valid
            } else if (!IsError(error)) {
                id userInfo = @{NSLocalizedDescriptionKey: [error description], PMKUnderlyingExceptionKey: error};
                error = [NSError errorWithDomain:PMKErrorDomain code:PMKInvalidUsageError userInfo:userInfo];
            }
            resolve(error);
        };

        id fulfiller = ^(id result){
            if (IsError(result))
                PMKLog(@"PromiseKit: Warning: PMKFulfiller called with NSError.");
            resolve(result);
        };

        block(fulfiller, rejecter);
    }];
}

.這個(gè)函數(shù)傳入帶有兩個(gè)參數(shù)的block 這兩個(gè)參數(shù)也同樣是個(gè)block 芦拿。類型分別吃PMKFulfiller 和 PMKRejecter
2 這里構(gòu)建了兩個(gè)block 士飒。再將兩個(gè)block(rejecter 和 fulfiller) 傳給外界了。
3 . 要是外界調(diào)用 fulfiller block 蔗崎,調(diào)用 PMKResolver 類型block 酵幕。從上面的分析我們知道,這個(gè)就是promise的正常處理缓苛。
4 .要是外界調(diào)用rejecter block芳撒,這里檢查傳入的error 要是nil 就生成一個(gè)NSError, 要是傳入的error 是promise 并且結(jié)果是error ,那么認(rèn)為合法未桥,要是傳入的數(shù)據(jù)不是error笔刹,誤入調(diào)用rejecter,我們我們將這個(gè)error 重新包裝成一個(gè)NSError 類型的error 調(diào)用 PMKResolver 類型的resolve 對(duì)error進(jìn)行處理冬耿。

這里我們看出來(lái)舌菜,這里對(duì)promise的結(jié)果又做了區(qū)分,rejecter 回調(diào)的結(jié)果一定是NSError 或者結(jié)果是NSError的promise 亦镶,而fulfiller 就是正常的結(jié)果日月。

看到這里我們可以對(duì)promise的成員變量做個(gè)總結(jié)了

1 dispatch_queue_t _promiseQueue; 這個(gè)不用過(guò)多解釋袱瓮,就是promise的queue
NSMutableArray *_handlers; 這個(gè)裝有 當(dāng)前promise要是有結(jié)果,需要將這個(gè)結(jié)果傳遞給其他的promise爱咬。
id _result; 這個(gè)結(jié)果有幾種情況 尺借,沒(méi)有值 , NSError精拟,promise和其他id類型對(duì)象燎斩。(后面還有個(gè)PMKError 歸類到NSError中)

這里其實(shí)就產(chǎn)生了一個(gè)鏈條


image.png

鏈條的傳遞必須是鏈條前端的promise 有結(jié)果了,后面的promise才能執(zhí)行蜂绎。

promise狀態(tài) 函數(shù)
- (BOOL)pending {
    id result = PMKGetResult(self);
    if (IsPromise(result)) {
        return [result pending];
    } else
        return result == nil;
}

- (BOOL)resolved {
    return PMKGetResult(self) != nil;
}

- (BOOL)fulfilled {
    id result = PMKGetResult(self);
    return result != nil && !IsError(result);
}

- (BOOL)rejected {
    id result = PMKGetResult(self);
    return result != nil && IsError(result);
}

- (id)value {
    id result = PMKGetResult(self);
    if (IsPromise(result))
        return [(PMKPromise *)result value];
    if ([result isKindOfClass:[PMKArray class]])
        return ((PMKArray *)result)[0];
    if (result == PMKNull)
        return nil;
    else
        return result;
}

這些函數(shù)狀態(tài)函數(shù)都是根據(jù)result 來(lái)做判斷的

1 - (BOOL)pending 瘫里,這個(gè)狀態(tài)代表promise有沒(méi)有被處理過(guò),或者處理后結(jié)果還是promise 荡碾,但是這個(gè)promise 的_result 還是nil谨读。沒(méi)有被處理過(guò)(fulfiller 傳入的參數(shù)是一個(gè)沒(méi)有被處理過(guò)的promise)。
2** (BOOL)resolved** ,這個(gè)代表promise是否被解決了坛吁。
3- (BOOL)fulfilled劳殖, 這個(gè)代表這個(gè)promise 解決的結(jié)果是否是正確的
4 - (BOOL)rejected,這個(gè)代表這個(gè)promise 解決的結(jié)果是不是error
5 - (id)value, 獲取promise的值,這里需要注意拨脉,要是promose的result 是 PMKPromise 哆姻,需要特殊處理,不是直接返回玫膀。

promise 鏈條中的其他函數(shù)方法
- (PMKPromise *(^)(id))then;
- (PMKPromise *(^)(id))thenInBackground;
- (PMKPromise *(^)(id))catch;
- (PMKPromise *(^)(void(^)(void)))finally;
- (PMKPromise *(^)(dispatch_queue_t, id))thenOn;
- (PMKPromise *(^)(dispatch_queue_t, id))catchOn;
- (PMKPromise *(^)(dispatch_queue_t, void(^)(void)))finallyOn;
+ (PMKPromise *)promiseWithValue:(id)value;

看上面的函數(shù)矛缨,要么返回PMKPromise 對(duì)象本身,要么返回 返回值是PMKPromise 類型的block帖旨。這就是典型的鏈?zhǔn)秸{(diào)用了箕昭。并且我們也能看出來(lái),這些函數(shù)類似try catch finally 結(jié)構(gòu)

我們把他們分類看

  • (PMKPromise *(^)(id))then ;
    typedef PMKPromise *(^PMKResolveOnQueueBlock)(dispatch_queue_t, id block);
  • (PMKResolveOnQueueBlock)thenOn;
    這里 then 函數(shù)的返回值是一個(gè)block解阅, 傳入的參數(shù)是 block落竹,返 回值是PMKPromise
    而thenOn 返回的返回值也是一個(gè)block,不過(guò)參數(shù)是兩個(gè)货抄,一個(gè)是dispatch_queue_t 述召,第二個(gè)是block
- (PMKPromise *(^)(id))then {
    return ^(id block){
        return self.thenOn(dispatch_get_main_queue(), block);
    };
}

then函數(shù)調(diào)用thenOn 線程傳入的是主線程。
重點(diǎn)看thenOn

- (PMKResolveOnQueueBlock)thenOn {
    return [self resolved:^(id result) {
        if (IsPromise(result))
            return ((PMKPromise *)result).thenOn;

        if (IsError(result)) return ^(dispatch_queue_t q, id block) {
            return [PMKPromise promiseWithValue:result];
        };

        return ^(dispatch_queue_t q, id block) {

            // HACK we seem to expose some bug in ARC where this block can
            // be an NSStackBlock which then gets deallocated by the time
            // we get around to using it. So we force it to be malloc'd.
            block = [block copy];

            return dispatch_promise_on(q, ^{
                return pmk_safely_call_block(block, result);
            });
        };
    }
    pending:^(id result, PMKPromise *next, dispatch_queue_t q, id block, void (^resolve)(id)) {
        if (IsError(result))
            PMKResolve(next, result);
        else dispatch_async(q, ^{
            resolve(pmk_safely_call_block(block, result));
        });
    }];
}

這里只調(diào)用了一個(gè)函數(shù)
*- (id)resolved:(PMKResolveOnQueueBlock(^)(id result))mkresolvedCallback
pending:(void(^)(id result, PMKPromise next, dispatch_queue_t q, id block, void (^resolver)(id)))mkpendingCallback

傳入給這個(gè)函數(shù)的兩個(gè)值在介紹上面的這個(gè)函數(shù)時(shí)候介紹

- (id)resolved:(PMKResolveOnQueueBlock(^)(id result))mkresolvedCallback
       pending:(void(^)(id result, PMKPromise *next, dispatch_queue_t q, id block, void (^resolver)(id)))mkpendingCallback
{
    __block PMKResolveOnQueueBlock callBlock;
    __block id result;
    
    dispatch_sync(_promiseQueue, ^{
        if ((result = _result))
            return;

        callBlock = ^(dispatch_queue_t q, id block) {

            // HACK we seem to expose some bug in ARC where this block can
            // be an NSStackBlock which then gets deallocated by the time
            // we get around to using it. So we force it to be malloc'd.
            block = [block copy];

            __block PMKPromise *next = nil;

            dispatch_barrier_sync(_promiseQueue, ^{
                if ((result = _result))
                    return;

                __block PMKPromiseFulfiller resolver;
                next = [PMKPromise new:^(PMKPromiseFulfiller fulfill, PMKPromiseRejecter reject) {
                    resolver = ^(id o){
                        if (IsError(o)) reject(o); else fulfill(o);
                    };
                }];
                [_handlers addObject:^(id value){
                    mkpendingCallback(value, next, q, block, resolver);
                }];
            });
            
            // next can still be `nil` if the promise was resolved after
            // 1) `-thenOn` read it and decided which block to return; and
            // 2) the call to the block.

            return next ?: mkresolvedCallback(result)(q, block);
        };
    });

    // We could just always return the above block, but then every caller would
    // trigger a barrier_sync on the promise queue. Instead, if we know that the
    // promise is resolved (since that makes it immutable), we can return a simpler
    // block that doesn't use a barrier in those cases.

    return callBlock ?: mkresolvedCallback(result);
}

1 這個(gè)函數(shù)的參數(shù)有兩個(gè)蟹地,mkresolvedCallback 和 mkpendingCallback积暖。
2 mkresolvedCallback 參數(shù)是個(gè)block ,參數(shù)是result怪与,返回值是一個(gè)PMKResolveOnQueueBlock類型的block夺刑,這個(gè)類型正好和thenOn的返回值是一個(gè)類型。
3 mkpendingCallback 也是一個(gè)block琼梆,參數(shù)有五個(gè)性誉,分別是id類型的result 窿吩,PMKPromise類型的next,dispatch_queue_t 類型的q错览,id類型的block和入?yún)⑹莍d 返回值是void的block 纫雁,命名是resolver。

具體分析下這個(gè)函數(shù)

1 聲明一個(gè)變量 callBack 和 result
2 在promise 的_promiseQueue 同步獲取下_result ,要是_result 有結(jié)果了倾哺,那么調(diào)用mkresolvedCallback 入?yún)?shù)是result 轧邪,那么就會(huì)返回thenOn的所需要的返回類型的值。這里我們看看mkresolvedCallback 執(zhí)行干了什么事情羞海。需要返回thenOn 中看

^(id result) {
        if (IsPromise(result))
            return ((PMKPromise *)result).thenOn;

        if (IsError(result)) return ^(dispatch_queue_t q, id block) {
            return [PMKPromise promiseWithValue:result];
        };

        return ^(dispatch_queue_t q, id block) {

            // HACK we seem to expose some bug in ARC where this block can
            // be an NSStackBlock which then gets deallocated by the time
            // we get around to using it. So we force it to be malloc'd.
            block = [block copy];

            return dispatch_promise_on(q, ^{
                return pmk_safely_call_block(block, result);
            });
        };
    }

這里我們知道傳入的result 是當(dāng)前promise_result 值忌愚。
判斷要是 result 是 promise,那么就接著調(diào)用 result的thenOn 却邓。
要是result 是 error硕糊,那么我們返回一個(gè)PMKResolveOnQueueBlock類型的block,這里需要注意的是執(zhí)行這個(gè)block腊徙,直接返回帶有result結(jié)果的PMKPromise 简十。(因?yàn)槭莈rror,block都給拋棄掉了)
正常的result結(jié)果撬腾,那我們返回一個(gè)PMKResolveOnQueueBlock類型的block螟蝙。這里需要注意,我們要是執(zhí)行這個(gè)block民傻,那么我們首先要對(duì)參數(shù)block執(zhí)行下copy(參數(shù)block可能在棧上胰默,被釋放),調(diào)用PMKPromise dispatch_promise_on(dispatch_queue_t queue, id block) 返回一個(gè)PMKpromise.
這里還有個(gè)函數(shù)
id pmk_safely_call_block(id frock, id result)*漓踢。這個(gè)函數(shù)就是對(duì)block的解析

id pmk_safely_call_block(id frock, id result) {
    assert(frock);

    if (result == PMKNull)
        result = nil;

    @try {
        NSMethodSignature *sig = NSMethodSignatureForBlock(frock);
        const NSUInteger nargs = sig.numberOfArguments;
        const char rtype = sig.methodReturnType[0];

        #define call_block_with_rtype(type) ({^type{ \
            switch (nargs) { \
                case 1: \
                    return ((type(^)(void))frock)(); \
                case 2: { \
                    const id arg = [result class] == [PMKArray class] ? ((PMKArray *)result)[0] : result; \
                    return ((type(^)(id))frock)(arg); \
                } \
                case 3: { \
                    type (^block)(id, id) = frock; \
                    return [result class] == [PMKArray class] \
                        ? block(((PMKArray *)result)[0], ((PMKArray *)result)[1]) \
                        : block(result, nil); \
                } \
                case 4: { \
                    type (^block)(id, id, id) = frock; \
                    return [result class] == [PMKArray class] \
                        ? block(((PMKArray *)result)[0], ((PMKArray *)result)[1], ((PMKArray *)result)[2]) \
                        : block(result, nil, nil); \
                } \
                default: \
                    @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"PromiseKit: The provided block’s argument count is unsupported." userInfo:nil]; \
            }}();})

        switch (rtype) {
            case 'v':
                call_block_with_rtype(void);
                return PMKNull;
            case '@':
                return call_block_with_rtype(id) ?: PMKNull;
            case '*': {
                char *str = call_block_with_rtype(char *);
                return str ? @(str) : PMKNull;
            }
            case 'c': return @(call_block_with_rtype(char));
            case 'i': return @(call_block_with_rtype(int));
            case 's': return @(call_block_with_rtype(short));
            case 'l': return @(call_block_with_rtype(long));
            case 'q': return @(call_block_with_rtype(long long));
            case 'C': return @(call_block_with_rtype(unsigned char));
            case 'I': return @(call_block_with_rtype(unsigned int));
            case 'S': return @(call_block_with_rtype(unsigned short));
            case 'L': return @(call_block_with_rtype(unsigned long));
            case 'Q': return @(call_block_with_rtype(unsigned long long));
            case 'f': return @(call_block_with_rtype(float));
            case 'd': return @(call_block_with_rtype(double));
            case 'B': return @(call_block_with_rtype(_Bool));
            case '^':
                if (strcmp(sig.methodReturnType, "^v") == 0) {
                    call_block_with_rtype(void);
                    return PMKNull;
                }
                // else fall through!
            default:
                @throw PMKE(@"Unsupported method signature… Why not fork and fix?");
        }
    } @catch (id e) {
      #ifdef PMK_RETHROW_LIKE_A_MOFO
        if ([e isKindOfClass:[NSException class]] && (
            [e name] == NSGenericException ||
            [e name] == NSRangeException ||
            [e name] == NSInvalidArgumentException ||
            [e name] == NSInternalInconsistencyException ||
            [e name] == NSObjectInaccessibleException ||
            [e name] == NSObjectNotAvailableException ||
            [e name] == NSDestinationInvalidException ||
            [e name] == NSPortTimeoutException ||
            [e name] == NSInvalidSendPortException ||
            [e name] == NSInvalidReceivePortException ||
            [e name] == NSPortSendException ||
            [e name] == NSPortReceiveException))
                @throw e;
      #endif
        return NSErrorFromException(e);
    }
}

這個(gè)方法傳入的參數(shù)有兩個(gè)牵署,第一個(gè)參數(shù)是block,第二個(gè)參數(shù)是返回的結(jié)果(鏈條中上一個(gè)promise產(chǎn)生的結(jié)果)彭雾。
這個(gè)方法是將block 轉(zhuǎn)換成函數(shù)簽名碟刺,通過(guò)函數(shù)簽名方法獲取這個(gè)block的參數(shù)
static NSMethodSignature *NSMethodSignatureForBlock(id block) 這個(gè)方法是對(duì)block進(jìn)行方法解析出簽名锁保,將block 轉(zhuǎn)換成函數(shù)簽名薯酝。這樣我們就通過(guò)這個(gè)函數(shù)簽名知道了這個(gè)block的參數(shù)以及返回值,知道了參數(shù)和返回值,我們就可以自己構(gòu)造block了爽柒。

PMKPromise *dispatch_promise_on(dispatch_queue_t queue, id block) {
    return [PMKPromise new:^(void(^fulfiller)(id), void(^rejecter)(id)){
        dispatch_async(queue, ^{
            id result = pmk_safely_call_block(block, nil);
            if (IsError(result))
                rejecter(result);
            else
                fulfiller(result);
        });
    }];
}

1.首先明確一點(diǎn)吴菠,這個(gè)函數(shù)返回一個(gè)PMKPromise
2 . 調(diào)用+ (instancetype)new:(void(^)(PMKFulfiller, PMKRejecter))block 函數(shù),這個(gè)函數(shù)前面分析過(guò)會(huì)給外界執(zhí)行本fulfiller 和 rejecter 的指針
3.這里獲取到fulfiller 和 rejecter 的指針沒(méi)有做保留處理浩村,直接執(zhí)行了做葵。(pmk_safely_call_block 就是對(duì)block進(jìn)行解析執(zhí)行)
4 ** pmk_safely_call_block** 執(zhí)行的block 是 在thenOn(行數(shù)323行的block),

               return pmk_safely_call_block(block, result);

看到這里想明白了就知道了323行的這個(gè)block是外界傳入的block,result是front 的promise的結(jié)果心墅,意思是把front 的promise的結(jié)果傳遞給我們thenOn 后面跟人的block

到這里酿矢,我們分析完畢了要是front 的promise 有結(jié)果的回調(diào)順序
總結(jié)下如圖


FlowchartDiagram1.png

要是front promise 沒(méi)有結(jié)果呢榨乎。這說(shuō)明front promise還沒(méi)有結(jié)果傳遞過(guò)來(lái)。
返回到- (id)resolved:(PMKResolveOnQueueBlock(^)(id result))mkresolvedCallback
pending:(void(^)(id result, PMKPromise *next, dispatch_queue_t q, id block, void (^resolver)(id)))mkpendingCallback函數(shù)

1.生成PMKResolveOnQueueBlock類型的一個(gè)block瘫筐,給callBack賦值蜜暑。
2.并且把這個(gè)新生成的block返回。暫時(shí)標(biāo)記為block2 策肝。這個(gè)block2 接受thenOn傳入的的dispatch_queue_t q, id block
我們看看 block2 干了啥事情
1 copy 將棧上的block copy到堆上
2 同步在當(dāng)前隊(duì)列上看promise的_result肛捍,有_result,直接返回之众,調(diào)用mkresolvedCallback(result)(q, block); 結(jié)束拙毫。(這里看著有點(diǎn)頭大,不過(guò)我們分開(kāi)看就好看了多了棺禾,mkresolvedCallback(result) 返回的是PMKResolveOnQueueBlock 缀蹄,PMKResolveOnQueueBlock執(zhí)行需要兩個(gè)參數(shù) dispatch_queue_t q, id block ,因此后面又有兩個(gè)括號(hào)跟著兩個(gè)參數(shù)膘婶。其實(shí)和剛開(kāi)始沒(méi)有參數(shù)的邏輯是一樣的)
3 同步在當(dāng)前隊(duì)列上看promise的_result 袍患,沒(méi)有_result .那么我們就重新生成一個(gè)PMKpromise 對(duì)象,將這個(gè)對(duì)象返回竣付。這里需要注意的是

 next = [PMKPromise new:^(PMKPromiseFulfiller fulfill, PMKPromiseRejecter reject) {
                    resolver = ^(id o){
                        if (IsError(o)) reject(o); else fulfill(o);
                    };
                }];
                [_handlers addObject:^(id value){
                    mkpendingCallback(value, next, q, block, resolver);
                }];

因?yàn)閏urrent的promise 還沒(méi)有結(jié)果诡延,所以,我們新生成的next promise 的 Fulfiller 和Rejecter 都不能執(zhí)行古胆,需要讓current promise保存next promise 的Fulfiller 和Rejecter 确镊,當(dāng)current promise 有結(jié)果了,將結(jié)果傳遞給next promise 的Fulfiller 或者Rejecter铭拧。
我們知道淆游,promise鏈條的傳遞是通過(guò)_handle 來(lái)傳遞的,_handle 中保存的是一個(gè)block棺牧,類型是^(id value){},參數(shù)是current promise的結(jié)果巫糙,當(dāng)promise 有結(jié)果的時(shí)候,會(huì)調(diào)用_handle中的所有block颊乘。因此這里我們需要將next promise 的Fulfiller 和Rejecter 加入到current promise的_handle中去参淹。
這里我們保存next promise 的fulfiller 和Rejecter 是通過(guò)一個(gè)block 來(lái)保存的。這個(gè)block 很簡(jiǎn)單乏悄,參數(shù)就一個(gè)就是結(jié)果了浙值,根據(jù)結(jié)果選擇fulfiller 和Rejecter 執(zhí)行
這里我們看看當(dāng)_handles 里面的block 執(zhí)行的時(shí)候干了什么事情。當(dāng)block 執(zhí)行的時(shí)候檩小,我們會(huì)調(diào)用到mkpendingCallback block 這個(gè)block 傳入的參數(shù)比較多开呐,value就是current promise的result , next 就是next Promise ,q 是next 的dispatch_queue_t筐付,block 是thenOn傳入的block卵惦,resolver 保存的是next 的fulfiller 和Rejecter。
我們看看mkpendingCallback的實(shí)現(xiàn)

^(id result, PMKPromise *next, dispatch_queue_t q, id block, void (^resolve)(id)) {
        if (IsError(result))
            PMKResolve(next, result);
        else dispatch_async(q, ^{
            resolve(pmk_safely_call_block(block, result));
        });
    }

實(shí)現(xiàn)很簡(jiǎn)單了瓦戚,判斷result 是 error 鸵荠,那么直接更新next promise 的結(jié)果,接著傳遞result 就是了
要是result不是error伤极,是正常返回值蛹找,那么我們切換到next 的的queue中,將result 結(jié)果傳遞到thenOn 傳入的block 中(pmk_safely_call_block(block, result))哨坪,接著調(diào)用resolve block庸疾,執(zhí)行next promise 的fulfiller 和Rejecter。調(diào)用結(jié)束

總結(jié)下沒(méi)有結(jié)果的情況


thenOnNotResult.png

到此当编,thenOn 的完整代碼分析完畢届慈。

總結(jié)下- (id)resolved:(PMKResolveOnQueueBlock(^)(id result))mkresolvedCallback
pending:(void(^)(id result, PMKPromise *next, dispatch_queue_t q, id block, void (^resolver)(id)))mkpendingCallback 這個(gè)函數(shù)

  1. mkresolvedCallback 當(dāng)promise 有結(jié)果的時(shí)候被調(diào)用
    2 mkpendingCallback 當(dāng)promise 沒(méi)有結(jié)果的時(shí)候被調(diào)用

接下來(lái)看

- (PMKPromise *(^)(id))catch;
- (PMKPromise *(^)(dispatch_queue_t, id))catchOn;
- (PMKResolveOnQueueBlock)catchOn {
    return [self resolved:^(id result) {
        if (IsPromise(result))
            return ((PMKPromise *)result).catchOn;
        
        if (IsError(result)) return ^(dispatch_queue_t q, id block) {

            // HACK we seem to expose some bug in ARC where this block can
            // be an NSStackBlock which then gets deallocated by the time
            // we get around to using it. So we force it to be malloc'd.
            block = [block copy];

            return dispatch_promise_on(q, ^{
                [PMKError consume:result];
                return pmk_safely_call_block(block, result);
            });
        };
        
        return ^(dispatch_queue_t q, id block) {
            return [PMKPromise promiseWithValue:result];
        };
    }
    pending:^(id result, PMKPromise *next, dispatch_queue_t q, id block, void (^resolve)(id)) {
        if (IsError(result)) {
            dispatch_async(q, ^{
                [PMKError consume:result];
                resolve(pmk_safely_call_block(block, result));
            });
        } else
            PMKResolve(next, result);
    }];
}

結(jié)構(gòu)和thenOn 一樣,只不過(guò)只是調(diào)用- (id)resolved:(PMKResolveOnQueueBlock(^)(id result))mkresolvedCallback
pending:(void(^)(id result, PMKPromise *next, dispatch_queue_t q, id block, void (^resolver)(id)))mkpendingCallback 這個(gè)函數(shù) 函數(shù)傳入的block不一樣而已

1 . mkresolvedCallback 樣式一樣忿偷,只不過(guò)和thenOn不同的是金顿,對(duì)正常數(shù)據(jù)直接返回了,而對(duì)NSerror數(shù)據(jù)進(jìn)行處理了鲤桥,和thenOn正好相反
2 mkpendingCallback 處理方式相同
3 其實(shí)也可以這么理解揍拆,thenOn在promise的鏈條上只處理正確數(shù)據(jù),對(duì)錯(cuò)誤數(shù)據(jù)只沿著promise鏈條傳遞下去茶凳。而catchOn只處理錯(cuò)誤數(shù)據(jù)嫂拴,對(duì)正確的數(shù)據(jù),對(duì)正確數(shù)據(jù)不處理贮喧,只沿著promise鏈條傳遞下去筒狠。

剩下一組,不管正確數(shù)據(jù)錯(cuò)誤數(shù)據(jù)都處理的api了

- (PMKPromise *(^)(void(^)(void)))finally;
- (PMKPromise *(^)(dispatch_queue_t, void(^)(void)))finallyOn;
- (PMKPromise *(^)(dispatch_queue_t, dispatch_block_t))finallyOn {
    return [self resolved:^(id passthru) {
        if (IsPromise(passthru))
            return ((PMKPromise *)passthru).finallyOn;

        return ^(dispatch_queue_t q, dispatch_block_t block) {

            // HACK we seem to expose some bug in ARC where this block can
            // be an NSStackBlock which then gets deallocated by the time
            // we get around to using it. So we force it to be malloc'd.
            block = [block copy];

            return dispatch_promise_on(q, ^{
                block();
                return passthru;
            });
        };
    } pending:^(id passthru, PMKPromise *next, dispatch_queue_t q, dispatch_block_t block, void (^resolve)(id)) {
        dispatch_async(q, ^{
            @try {
                block();
                resolve(passthru);
            } @catch (id e) {
                resolve(NSErrorFromException(e));
            }
        });
    }];
}
  1. 這個(gè)finallyOn 傳入的block 只能是沒(méi)有參數(shù)的block箱沦。
    2 返回結(jié)果辩恼,不對(duì)結(jié)果做任何處理,谓形。

這里主要的api 都解決了灶伊。看看其他的細(xì)節(jié)問(wèn)題

+ (instancetype)promiseWithAdapter:(void (^)(PMKAdapter))block {
    return [self promiseWithResolver:^(PMKResolver resolve) {
        block(^(id value, id error){
            resolve(error ?: value);
        });
    }];
}

這個(gè) 根據(jù)外面是否傳入error 來(lái)判斷結(jié)果套耕,如果傳入error那么我們就將error沿著promise谁帕,否則沿著正常數(shù)據(jù)傳遞
還有兩個(gè)類似的方法

+ (instancetype)promiseWithIntegerAdapter:(void (^)(PMKIntegerAdapter))block {
    return [self promiseWithResolver:^(PMKResolver resolve) {
        block(^(NSInteger value, id error){
            if (error) {
                resolve(error);
            } else {
                resolve(@(value));
            }
        });
    }];
}

+ (instancetype)promiseWithBooleanAdapter:(void (^)(PMKBooleanAdapter adapter))block {
    return [self promiseWithResolver:^(PMKResolver resolve) {
        block(^(BOOL value, id error){
            if (error) {
                resolve(error);
            } else {
                resolve(@(value));
            }
        });
    }];
}

以上兩個(gè)不做介紹,寫個(gè)小例子冯袍,看看就行了

    [PMKPromise promiseWithAdapter:^(PMKAdapter adapter) {
        adapter(@"adapter",nil);
    }].then(^(NSString *str){
        NSLog(@"%@",str);
    });
最多支持三個(gè)參數(shù)實(shí)現(xiàn)

我們知道我們?cè)谡{(diào)用promise 的fulfiller 或者是rejecter 的時(shí)候傳入的參數(shù)是一個(gè),而在Then,Catch 的時(shí)候,我們傳入的block可以支持最多不超過(guò)三個(gè)參數(shù)康愤,這如何實(shí)現(xiàn)的呢儡循?

其實(shí)fulfiller 或者是rejecter 傳入的數(shù)據(jù)要是多個(gè)參數(shù)的時(shí)候,我們是需要將其打包成 PMKArray 數(shù)組的征冷,這個(gè)數(shù)組其實(shí)就是current 的result了择膝。在傳遞到next promise的時(shí)候,我們通過(guò)id pmk_safely_call_block(id frock, id result) 检激,解析出next Promise 傳入的block的參數(shù)肴捉,根據(jù)參數(shù)個(gè)數(shù),從 PMKArray數(shù)組中依次取出來(lái)叔收。

特殊API

promiseKit 支持 when 和until 齿穗。when 就是當(dāng)所有的任務(wù)執(zhí)行完畢在執(zhí)行我。我們看看如何實(shí)現(xiàn)的when饺律。

+ (PMKPromise *)when:(id)promises {
    if ([promises conformsToProtocol:@protocol(NSFastEnumeration)]) {
        return [self all:promises];
    } else if (promises) {
        return [self all:@[promises]].then(^(NSArray *values){
            return [values objectAtIndex:0];
        });
    } else {
        return [PMKPromise promiseWithValue:nil];
    }
}

+ (PMKPromise *)all:(id<NSFastEnumeration, NSObject>)promises {
    __block NSUInteger count = [(id)promises count];  // FIXME
    
    if (count == 0)
        return [PMKPromise promiseWithValue:promises];

    // Keep a reference to the newly created
    // promise so we can check if it's resolved
    // when one of the passed in promises fails.
    __block PMKPromise *newPromise = nil;

    #define rejecter(key) ^(NSError *err){ \
        if (newPromise.resolved) \
            return; \
        NSMutableDictionary *userInfo = err.userInfo.mutableCopy; \
        [userInfo setObject:key forKey:PMKFailingPromiseIndexKey]; \
        err = [NSError errorWithDomain:err.domain code:err.code userInfo:userInfo]; \
        rejecter(err); \
    }

    if ([promises isKindOfClass:[NSDictionary class]])
        return newPromise = [PMKPromise new:^(PMKPromiseFulfiller fulfiller, PMKPromiseRejecter rejecter){
            NSDictionary *promiseDictionary = (NSDictionary *) promises;
            NSMutableDictionary *results = [NSMutableDictionary new];
            for (id key in promiseDictionary) {
                PMKPromise *promise = [promiseDictionary objectForKey:key];
                if (![promise isKindOfClass:[PMKPromise class]])
                    promise = [PMKPromise promiseWithValue:promise];
                promise.catch(rejecter(key));
                promise.then(^(id o){
                    if (o)
                        [results setObject:o forKey:key];
                    if (--count == 0)
                        fulfiller(results);
                });
            }
        }];

    return newPromise = [PMKPromise new:^(PMKPromiseFulfiller fulfiller, PMKPromiseRejecter rejecter){
        NSPointerArray *results = nil;
      #if TARGET_OS_IPHONE
        results = [NSPointerArray strongObjectsPointerArray];
      #else
        if ([[NSPointerArray class] respondsToSelector:@selector(strongObjectsPointerArray)]) {
            results = [NSPointerArray strongObjectsPointerArray];
        } else {
          #pragma clang diagnostic push
          #pragma clang diagnostic ignored "-Wdeprecated-declarations"
            results = [NSPointerArray pointerArrayWithStrongObjects];
          #pragma clang diagnostic pop
        }
      #endif
        results.count = count;

        NSUInteger ii = 0;

        for (__strong PMKPromise *promise in promises) {
            if (![promise isKindOfClass:[PMKPromise class]])
                promise = [PMKPromise promiseWithValue:promise];
            promise.catch(rejecter(@(ii)));
            promise.then(^(id o){
                [results replacePointerAtIndex:ii withPointer:(__bridge void *)(o ?: [NSNull null])];
                if (--count == 0)
                    fulfiller(results.allObjects);
            });
            ii++;
        }
    }];

    #undef rejecter
}

第一個(gè)函數(shù)很簡(jiǎn)單不做介紹窃页,主要看第二個(gè)函數(shù)

1 參數(shù) 是promises ,必須能枚舉的集合吧复濒。數(shù)組字典set都可以脖卖。
2 要是集合數(shù)量是0 ,那么直接返回一個(gè)PMKPromise巧颈,這里也是無(wú)奈啊畦木,這個(gè)值不知道穿啥好,就把自己傳回去了

  1. 要是promises 是個(gè)NSDictionary 砸泛,我們創(chuàng)建一個(gè)PMKPromise 命名為newPromise馋劈。我們知道這個(gè)newPromise 有兩個(gè)狀態(tài)回調(diào)block,分別是fulfillerrejecter晾嘶,通過(guò)這兩個(gè)block能將結(jié)果傳入newPromise 中妓雾,因此,這里我們就將在字典中的所有promise 都分別或者通過(guò)字典值生成的promise 分別持有fulfillerrejecter垒迂,只要有一個(gè)promise 結(jié)果是NSerror 械姻,那么我們就結(jié)束newPromise,讓其保存NSError結(jié)果机断。所有promise要是沒(méi)有錯(cuò)誤楷拳,當(dāng)每一個(gè)promise 結(jié)束的時(shí)候,將所有promise共享的計(jì)數(shù)器減1 吏奸,當(dāng)計(jì)數(shù)器變?yōu)? 的時(shí)候欢揖,也就是最后一個(gè)promise完成的時(shí)候,我們?cè)賹ewPromise 的fulfiller 調(diào)用奋蔚,讓其newPromise 結(jié)束她混。數(shù)組同理烈钞。

說(shuō)的不明確,看圖就行了坤按,關(guān)系圖


image.png

這里還有個(gè)until 用法毯欣,我就寫個(gè)簡(jiǎn)單代碼體會(huì)下。

 array = [NSMutableArray array];
   PMKPromise * p =  [PMKPromise promiseWithAdapter:^(PMKAdapter adapter) {
        adapter(@"nihao",nil);
    }];
    [array addObject:p];
    p =  [PMKPromise promiseWithAdapter:^(PMKAdapter adapter) {
        NSError * error = [NSError errorWithDomain:PMKErrorDomain code:PMKInvalidUsageError userInfo:nil];;
        adapter(@"error",error);
    }];
    [array addObject:p];
    [array addObject:@"dd"];
    [PMKPromise until:^id{
        return array;
    } catch:^(NSError * error){
        NSDictionary * dic = [error userInfo];
        NSNumber * num =[dic objectForKey:PMKFailingPromiseIndexKey];
        [array removeObjectAtIndex:num.integerValue];
        NSLog(@"%@",[error description]);
    }].then(^(id result){
        NSLog(@"%@",result);
    });

運(yùn)行結(jié)果

2018-08-21 16:21:45.645773+0800 OriginCodeAnalytical[98249:1362520] Error Domain=PMKErrorDomain Code=3 "(null)" UserInfo={PMKFailingPromiseIndexKey=1}
2018-08-21 16:21:45.647217+0800 OriginCodeAnalytical[98249:1362520] (
    nihao,
    dd
)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末臭脓,一起剝皮案震驚了整個(gè)濱河市酗钞,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌来累,老刑警劉巖砚作,帶你破解...
    沈念sama閱讀 212,599評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異嘹锁,居然都是意外死亡葫录,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門兼耀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)压昼,“玉大人,你說(shuō)我怎么就攤上這事瘤运∏舷迹” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 158,084評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵拯坟,是天一觀的道長(zhǎng)但金。 經(jīng)常有香客問(wèn)我,道長(zhǎng)郁季,這世上最難降的妖魔是什么冷溃? 我笑而不...
    開(kāi)封第一講書人閱讀 56,708評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮梦裂,結(jié)果婚禮上似枕,老公的妹妹穿的比我還像新娘。我一直安慰自己年柠,他們只是感情好凿歼,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,813評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著冗恨,像睡著了一般答憔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上掀抹,一...
    開(kāi)封第一講書人閱讀 50,021評(píng)論 1 291
  • 那天虐拓,我揣著相機(jī)與錄音,去河邊找鬼傲武。 笑死蓉驹,一個(gè)胖子當(dāng)著我的面吹牛城榛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播戒幔,決...
    沈念sama閱讀 39,120評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼吠谢,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼土童!你這毒婦竟也來(lái)了诗茎?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,866評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤献汗,失蹤者是張志新(化名)和其女友劉穎敢订,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體罢吃,經(jīng)...
    沈念sama閱讀 44,308評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡楚午,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,633評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了尿招。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片矾柜。...
    茶點(diǎn)故事閱讀 38,768評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖就谜,靈堂內(nèi)的尸體忽然破棺而出怪蔑,到底是詐尸還是另有隱情,我是刑警寧澤丧荐,帶...
    沈念sama閱讀 34,461評(píng)論 4 333
  • 正文 年R本政府宣布缆瓣,位于F島的核電站,受9級(jí)特大地震影響虹统,放射性物質(zhì)發(fā)生泄漏弓坞。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,094評(píng)論 3 317
  • 文/蒙蒙 一车荔、第九天 我趴在偏房一處隱蔽的房頂上張望渡冻。 院中可真熱鬧,春花似錦忧便、人聲如沸族吻。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,850評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)呼奢。三九已至,卻和暖如春切平,著一層夾襖步出監(jiān)牢的瞬間握础,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,082評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工悴品, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留禀综,地道東北人简烘。 一個(gè)月前我還...
    沈念sama閱讀 46,571評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像定枷,于是被迫代替她去往敵國(guó)和親孤澎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,666評(píng)論 2 350

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