PromiseKit源码分析

废话不多说,本博就开工。

源码地址
本博客没有关注swift ,因此还是采用oc方式分析源码,源码来自pod 更新

pod 'PromiseKit', '~> 1.0'

概述

promise 是用来处理回调地狱的,借鉴图


image

基本使用

本文看alert 的promise

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

结果呢


image.png

这是怎么实现的呢?进入正题。


promise 源码实现

引出核心代码

@interface PMKAlertViewDelegater : NSObject  {
@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 中我们能看出来,这里调用- (PMKPromise *)promise

1.我们会创建UIAlertView的一个代理并且Retain

  1. 将对象设置为UIAlertView 的代理
    3.展示Alert
    4.生成一个promise

这里重点是第四步生成promise。

这里我们可以看看其他零散的小知识点宏定义

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 都是采用关联引用进行保存对象
PMKRelease 采用关联引用对对象近视释放 ,成对出现的。

这里还有个限制参数的宏定义,编译阶段就知道了参数的个数

#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 代表的,代表无限参数
怎么看这个宏定义呢?我们就是把参数带人一步步看就知道了

假设我们的参数是@1 ,@2,@3 这个宏定义运行的结果是 __PMKArrayWithCount(3, @1, @2, @3);可以帮助我们自动获取参数的个数,不过这里最多只支持三个
1 PMKManifold(@1 ,@2,@3) 转换成__PMKManifold(@1 ,@2,@3,3,2,1) VA_ARGS 换成 @1 ,@2,@3*
__PMKManifold(@1 ,@2,@3,3,2,1) 转换成 __PMKArrayWithCount(3, @1 ,@2,@3) 这里N 是3

这是宏定义的二次处理。编译阶段我们就知道参数的个数了。性能能改善一点是一点吧。

核心源码类PMKPromise

PMKPromise 类结构

这个类结构比较简单


PMKPromise.png
PMKPromise 类初始化

看了API 作者没有标记那个是真正的初始化API
真正生成对象的API是

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

默认的+init 方法给重写设置无效

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;
}

这里我们看传入的参数只有一个PMKResolver类型的block

1 入参: 传入PMKResolver 类型block
2 初始化: 创建PMKPromise 对象,分配空间
3 给PMKPromise 对象 的成员变量_promiseQueue设置值。queue 是一个DISPATCH_QUEUE_CONCURRENT 类型的queue 。(Concurrent Dispatch Queue不过创建多少都没有问题,因为Concurrent Dispatch Queue所使用的线程由系统的XNU内核高效管理,不会影响系统性能。
这里上个图

image.png

4创建 数组给 _handlers 赋值
5 try catch 调用 PMKResolver 类型的block 。传入的参数是block ,类型是^(id result){}。 调用block 失败了,调用**static NSArray PMKSetResult(PMKPromise this, id result)
6 返回this

这里看完好多人肯定一头雾水,这是在干么。其实把,这里是我们只是创建了个PMKPromise ,我们采用了block的保存语句块的功能,将对这个PMKPromise 对象的处理放在了外面。如果外界需要对我处理,那么调用我给你外界的句柄 block。(这里要是传入的参数不对,那么我就直接对这个PMKPromise 做错误处理)

结构如下


image.png

我们先看看要是外界传入的参数block 不合法,我们调用的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 调用PMKSanitizeResult对结果进行处理下,保证结果不是nil。
2 在promise queue中获取下handle ,将handle处理为nil ,将成员变量_result 赋值(一定不是nil,nil代表这个promise还没有被处理,是promise的一种状态)
3 返回handles

这里没有对返回的handle 做处理

我们看看如何处理PMKPromise,外界调用这个block发生了什么事情

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

            PMKResolve(this, result);
        }

1.这里很简单, 调用static id PMKGetResult(PMKPromise this) 判断 PMKPromise 是否有结果,有结果就返回。(具体怎么返回看下面)
2 如果
* PMKPromise** 没有设置结果就调用*static void PMKResolve(PMKPromise this, id result) 将结果设置到PMKPromise 的变量_result 中(具体函数分析往下面看)

先看*static id PMKGetResult(PMKPromise this)

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

这个很简单,就是获取下PMKPromise 的成员变量 _result的值.不过是同步获取,意思是当前线程中获取下 结果返回。

再看下*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);
}

这算是对PMKPromise 处理的核心函数了

1 声明一个 block 命名set 。调用这个set block 。这个block中会先调用PMKSetResult,对这个promise 进行赋值操作,然后在处理所有的handle。(这里根据handle的调用和下文知道也是一个block
2 这里是个宏定义判断result 是不是promise
3 result 不是 promise 那么就调用set block
4 result 是promise,命名为next ,那么获取next这个promise 的 成员变量_result。要是这个promise 还没有设置结果,那么我们next的_handle 成员变量中要保存一个block,这个block是处理this promise的句柄(意思是next 调用set的时候,需要将result 告诉下this)。要是promise 的设置了结果,那么就调用set block

看到这里我估计好多人只是看懂了函数本身,但是整体没有看懂。因此在做个整体图明晰下


image.png

这里举例说明

类的成员变量
{
        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 中保存的是所有的其他的依赖结果的promise。不单单是一个。可以是多个。

这里我们再看看UIAlertView 调用的这个初始化方法

+ (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);
    }];
}

.这个函数传入带有两个参数的block 这两个参数也同样是个block 。类型分别吃PMKFulfiller 和 PMKRejecter
2 这里构建了两个block 。再将两个block(rejecter 和 fulfiller) 传给外界了。
3 . 要是外界调用 fulfiller block ,调用 PMKResolver 类型block 。从上面的分析我们知道,这个就是promise的正常处理。
4 .要是外界调用rejecter block,这里检查传入的error 要是nil 就生成一个NSError, 要是传入的error 是promise 并且结果是error ,那么认为合法,要是传入的数据不是error,误入调用rejecter,我们我们将这个error 重新包装成一个NSError 类型的error 调用 PMKResolver 类型的resolve 对error进行处理。

这里我们看出来,这里对promise的结果又做了区分,rejecter 回调的结果一定是NSError 或者结果是NSError的promise ,而fulfiller 就是正常的结果。

看到这里我们可以对promise的成员变量做个总结了

1 dispatch_queue_t _promiseQueue; 这个不用过多解释,就是promise的queue
NSMutableArray *_handlers; 这个装有 当前promise要是有结果,需要将这个结果传递给其他的promise。
id _result; 这个结果有几种情况 ,没有值 , NSError,promise和其他id类型对象。(后面还有个PMKError 归类到NSError中)

这里其实就产生了一个链条


image.png

链条的传递必须是链条前端的promise 有结果了,后面的promise才能执行。

promise状态 函数
- (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;
}

这些函数状态函数都是根据result 来做判断的

1 - (BOOL)pending ,这个状态代表promise有没有被处理过,或者处理后结果还是promise ,但是这个promise 的_result 还是nil。没有被处理过(fulfiller 传入的参数是一个没有被处理过的promise)。
2** (BOOL)resolved** ,这个代表promise是否被解决了。
3- (BOOL)fulfilled, 这个代表这个promise 解决的结果是否是正确的
4 - (BOOL)rejected,这个代表这个promise 解决的结果是不是error
5 - (id)value, 获取promise的值,这里需要注意,要是promose的result 是 PMKPromise ,需要特殊处理,不是直接返回。

promise 链条中的其他函数方法
- (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;

看上面的函数,要么返回PMKPromise 对象本身,要么返回 返回值是PMKPromise 类型的block。这就是典型的链式调用了。并且我们也能看出来,这些函数类似try catch finally 结构

我们把他们分类看

  • (PMKPromise *(^)(id))then ;
    typedef PMKPromise *(^PMKResolveOnQueueBlock)(dispatch_queue_t, id block);
  • (PMKResolveOnQueueBlock)thenOn;
    这里 then 函数的返回值是一个block, 传入的参数是 block,返 回值是PMKPromise
    而thenOn 返回的返回值也是一个block,不过参数是两个,一个是dispatch_queue_t ,第二个是block
- (PMKPromise *(^)(id))then {
    return ^(id block){
        return self.thenOn(dispatch_get_main_queue(), block);
    };
}

then函数调用thenOn 线程传入的是主线程。
重点看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));
        });
    }];
}

这里只调用了一个函数
*- (id)resolved:(PMKResolveOnQueueBlock(^)(id result))mkresolvedCallback
pending:(void(^)(id result, PMKPromise next, dispatch_queue_t q, id block, void (^resolver)(id)))mkpendingCallback

传入给这个函数的两个值在介绍上面的这个函数时候介绍

- (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 这个函数的参数有两个,mkresolvedCallback 和 mkpendingCallback。
2 mkresolvedCallback 参数是个block ,参数是result,返回值是一个PMKResolveOnQueueBlock类型的block,这个类型正好和thenOn的返回值是一个类型。
3 mkpendingCallback 也是一个block,参数有五个,分别是id类型的result ,PMKPromise类型的next,dispatch_queue_t 类型的q,id类型的block和入参是id 返回值是void的block ,命名是resolver。

具体分析下这个函数

1 声明一个变量 callBack 和 result
2 在promise 的_promiseQueue 同步获取下_result ,要是_result 有结果了,那么调用mkresolvedCallback 入参数是result ,那么就会返回thenOn的所需要的返回类型的值。这里我们看看mkresolvedCallback 执行干了什么事情。需要返回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 是当前promise_result 值。
判断要是 result 是 promise,那么就接着调用 result的thenOn 。
要是result 是 error,那么我们返回一个PMKResolveOnQueueBlock类型的block,这里需要注意的是执行这个block,直接返回带有result结果的PMKPromise 。(因为是error,block都给抛弃掉了)
正常的result结果,那我们返回一个PMKResolveOnQueueBlock类型的block。这里需要注意,我们要是执行这个block,那么我们首先要对参数block执行下copy(参数block可能在栈上,被释放),调用PMKPromise dispatch_promise_on(dispatch_queue_t queue, id block) 返回一个PMKpromise.
这里还有个函数
id pmk_safely_call_block(id frock, id result)*。这个函数就是对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);
    }
}

这个方法传入的参数有两个,第一个参数是block,第二个参数是返回的结果(链条中上一个promise产生的结果)。
这个方法是将block 转换成函数签名,通过函数签名方法获取这个block的参数
static NSMethodSignature *NSMethodSignatureForBlock(id block) 这个方法是对block进行方法解析出签名,将block 转换成函数签名。这样我们就通过这个函数签名知道了这个block的参数以及返回值,知道了参数和返回值,我们就可以自己构造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.首先明确一点,这个函数返回一个PMKPromise
2 . 调用+ (instancetype)new:(void(^)(PMKFulfiller, PMKRejecter))block 函数,这个函数前面分析过会给外界执行本fulfiller 和 rejecter 的指针
3.这里获取到fulfiller 和 rejecter 的指针没有做保留处理,直接执行了。(pmk_safely_call_block 就是对block进行解析执行)
4 ** pmk_safely_call_block** 执行的block 是 在thenOn(行数323行的block),

               return pmk_safely_call_block(block, result);

看到这里想明白了就知道了323行的这个block是外界传入的block,result是front 的promise的结果,意思是把front 的promise的结果传递给我们thenOn 后面跟人的block

到这里,我们分析完毕了要是front 的promise 有结果的回调顺序
总结下如图


FlowchartDiagram1.png

要是front promise 没有结果呢。这说明front promise还没有结果传递过来。
返回到- (id)resolved:(PMKResolveOnQueueBlock(^)(id result))mkresolvedCallback
pending:(void(^)(id result, PMKPromise *next, dispatch_queue_t q, id block, void (^resolver)(id)))mkpendingCallback函数

1.生成PMKResolveOnQueueBlock类型的一个block,给callBack赋值。
2.并且把这个新生成的block返回。暂时标记为block2 。这个block2 接受thenOn传入的的dispatch_queue_t q, id block
我们看看 block2 干了啥事情
1 copy 将栈上的block copy到堆上
2 同步在当前队列上看promise的_result,有_result,直接返回,调用mkresolvedCallback(result)(q, block); 结束。(这里看着有点头大,不过我们分开看就好看了多了,mkresolvedCallback(result) 返回的是PMKResolveOnQueueBlock ,PMKResolveOnQueueBlock执行需要两个参数 dispatch_queue_t q, id block ,因此后面又有两个括号跟着两个参数。其实和刚开始没有参数的逻辑是一样的)
3 同步在当前队列上看promise的_result ,没有_result .那么我们就重新生成一个PMKpromise 对象,将这个对象返回。这里需要注意的是

 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);
                }];

因为current的promise 还没有结果,所以,我们新生成的next promise 的 Fulfiller 和Rejecter 都不能执行,需要让current promise保存next promise 的Fulfiller 和Rejecter ,当current promise 有结果了,将结果传递给next promise 的Fulfiller 或者Rejecter。
我们知道,promise链条的传递是通过_handle 来传递的,_handle 中保存的是一个block,类型是^(id value){},参数是current promise的结果,当promise 有结果的时候,会调用_handle中的所有block。因此这里我们需要将next promise 的Fulfiller 和Rejecter 加入到current promise的_handle中去。
这里我们保存next promise 的fulfiller 和Rejecter 是通过一个block 来保存的。这个block 很简单,参数就一个就是结果了,根据结果选择fulfiller 和Rejecter 执行
这里我们看看当_handles 里面的block 执行的时候干了什么事情。当block 执行的时候,我们会调用到mkpendingCallback block 这个block 传入的参数比较多,value就是current promise的result , next 就是next Promise ,q 是next 的dispatch_queue_t,block 是thenOn传入的block,resolver 保存的是next 的fulfiller 和Rejecter。
我们看看mkpendingCallback的实现

^(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));
        });
    }

实现很简单了,判断result 是 error ,那么直接更新next promise 的结果,接着传递result 就是了
要是result不是error,是正常返回值,那么我们切换到next 的的queue中,将result 结果传递到thenOn 传入的block 中(pmk_safely_call_block(block, result)),接着调用resolve block,执行next promise 的fulfiller 和Rejecter。调用结束

总结下没有结果的情况


thenOnNotResult.png

到此,thenOn 的完整代码分析完毕。

总结下- (id)resolved:(PMKResolveOnQueueBlock(^)(id result))mkresolvedCallback
pending:(void(^)(id result, PMKPromise *next, dispatch_queue_t q, id block, void (^resolver)(id)))mkpendingCallback 这个函数

  1. mkresolvedCallback 当promise 有结果的时候被调用
    2 mkpendingCallback 当promise 没有结果的时候被调用

接下来看

- (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);
    }];
}

结构和thenOn 一样,只不过只是调用- (id)resolved:(PMKResolveOnQueueBlock(^)(id result))mkresolvedCallback
pending:(void(^)(id result, PMKPromise *next, dispatch_queue_t q, id block, void (^resolver)(id)))mkpendingCallback 这个函数 函数传入的block不一样而已

1 . mkresolvedCallback 样式一样,只不过和thenOn不同的是,对正常数据直接返回了,而对NSerror数据进行处理了,和thenOn正好相反
2 mkpendingCallback 处理方式相同
3 其实也可以这么理解,thenOn在promise的链条上只处理正确数据,对错误数据只沿着promise链条传递下去。而catchOn只处理错误数据,对正确的数据,对正确数据不处理,只沿着promise链条传递下去。

剩下一组,不管正确数据错误数据都处理的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. 这个finallyOn 传入的block 只能是没有参数的block。
    2 返回结果,不对结果做任何处理,。

这里主要的api 都解决了。看看其他的细节问题

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

这个 根据外面是否传入error 来判断结果,如果传入error那么我们就将error沿着promise,否则沿着正常数据传递
还有两个类似的方法

+ (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));
            }
        });
    }];
}

以上两个不做介绍,写个小例子,看看就行了

    [PMKPromise promiseWithAdapter:^(PMKAdapter adapter) {
        adapter(@"adapter",nil);
    }].then(^(NSString *str){
        NSLog(@"%@",str);
    });
最多支持三个参数实现

我们知道我们在调用promise 的fulfiller 或者是rejecter 的时候传入的参数是一个,而在Then,Catch 的时候,我们传入的block可以支持最多不超过三个参数,这如何实现的呢?

其实fulfiller 或者是rejecter 传入的数据要是多个参数的时候,我们是需要将其打包成 PMKArray 数组的,这个数组其实就是current 的result了。在传递到next promise的时候,我们通过id pmk_safely_call_block(id frock, id result) ,解析出next Promise 传入的block的参数,根据参数个数,从 PMKArray数组中依次取出来。

特殊API

promiseKit 支持 when 和until 。when 就是当所有的任务执行完毕在执行我。我们看看如何实现的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)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
}

第一个函数很简单不做介绍,主要看第二个函数

1 参数 是promises ,必须能枚举的集合吧。数组字典set都可以。
2 要是集合数量是0 ,那么直接返回一个PMKPromise,这里也是无奈啊,这个值不知道穿啥好,就把自己传回去了

  1. 要是promises 是个NSDictionary ,我们创建一个PMKPromise 命名为newPromise。我们知道这个newPromise 有两个状态回调block,分别是fulfillerrejecter,通过这两个block能将结果传入newPromise 中,因此,这里我们就将在字典中的所有promise 都分别或者通过字典值生成的promise 分别持有fulfillerrejecter,只要有一个promise 结果是NSerror ,那么我们就结束newPromise,让其保存NSError结果。所有promise要是没有错误,当每一个promise 结束的时候,将所有promise共享的计数器减1 ,当计数器变为0 的时候,也就是最后一个promise完成的时候,我们再将newPromise 的fulfiller 调用,让其newPromise 结束。数组同理。

说的不明确,看图就行了,关系图


image.png

这里还有个until 用法,我就写个简单代码体会下。

 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);
    });

运行结果

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
)

你可能感兴趣的:(PromiseKit源码分析)