廢話不多說(shuō),本博就開(kāi)工仿便。
源碼地址
本博客沒(méi)有關(guān)注swift 谦去,因此還是采用oc方式分析源碼,源碼來(lái)自pod 更新
pod 'PromiseKit', '~> 1.0'
概述
promise 是用來(lái)處理回調(diào)地獄的,借鑒圖
基本使用
本文看alert 的promise
UIAlertView * alertview=[[UIAlertView alloc]initWithTitle:@"alert" message:@"promiseTest" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"確定", nil];
[alertview promise].then(^{
NSLog(@"dddd");
});
結(jié)果呢
這是怎么實(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
- 將對(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 類初始化
看了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)如下
我們先看看要是外界傳入的參數(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è)整體圖明晰下
這里舉例說(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è)鏈條
鏈條的傳遞必須是鏈條前端的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é)下如圖
要是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é)果的情況
到此当编,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ù)
- 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));
}
});
}];
}
- 這個(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è)值不知道穿啥好,就把自己傳回去了
- 要是promises 是個(gè)NSDictionary 砸泛,我們創(chuàng)建一個(gè)PMKPromise 命名為newPromise馋劈。我們知道這個(gè)newPromise 有兩個(gè)狀態(tài)回調(diào)block,分別是fulfiller 和 rejecter晾嘶,通過(guò)這兩個(gè)block能將結(jié)果傳入newPromise 中妓雾,因此,這里我們就將在字典中的所有promise 都分別或者通過(guò)字典值生成的promise 分別持有fulfiller 和 rejecter垒迂,只要有一個(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)系圖
這里還有個(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
)