最近在尝试解决下载管理中,全部下载的速度问题,于是在github中试图寻找答案,无意中发现了Promise这个第三方库。它的作用如下
Future
is a sort of a placeholder object that you can create for a result that does not yet exist. Generally, the result of the
Future
is computed concurrently and can be later collected. Composing concurrent tasks in this way tends to result in faster, asynchronous, non-blocking parallel code.
@implementation MyViewController - (void)viewDidLoad { id rq = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://placekitten.com/320/320"]]; void (^handleError)(id) = ^(NSString *msg){ UIAlertView *alert = [[UIAlertView alloc] init… delegate:self …]; [alert show]; }; [NSURLConnection sendAsynchronousRequest:rq completionHandler:^(id response, id data, id error) { if (error) { handle([error localizedDescription]); } else { UIImage *image = [UIImage imageWithData:data]; if (!image) { handleError(@"Bad server response"); } else { self.imageView.image = image; } } }]; } - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { // hopefully we won’t ever have multiple UIAlertViews handled in this class [self dismissViewControllerAnimated:YES]; } @end
#import <PromiseKit.h> - (void)viewDidLoad { [NSURLConnection GET:@"http://placekitten.com/320/320"].then(^(UIImage *image) { self.imageView.image = image; }).catch(^(NSError *error){ UIAlertView *alert = [[UIAlertView alloc] initWithTitle:…]; [alert promise].then(^{ [self dismissViewControllerAnimated:YES]; }) }); }

A `Promise` represents the future value of a task.
To obtain the value of a `Promise`, call `then`. When the asynchronous task that this `Promise` represents has resolved successfully, the block you pass to `then` will be executed with the resolved value. If the `Promise` has already been resolved succesfully at the time you `then` the `Promise`, the block will be executed immediately.
Effective use of Promises involves chaining `then`s, where the return value from one `then` is fed as the value of the next, et cetera.
promise 代表了一个任务的未来的值,
UIAlertView * alert=[[UIAlertView alloc] initWithTitle:@"title" message:@"message" delegate:nil cancelButtonTitle:@"sure" otherButtonTitles:nil]; [alert promise].then(^(){ NSLog(@"excute!"); });
在创建 UI|AlertView之后调用它的promise对象,然后调用then就可以了。调用方法相当简单,具体使用可以参考:http://promisekit.org。
- (PMKPromise *)promise { PMKAlertViewDelegater *d = [PMKAlertViewDelegater new]; PMKRetain(d); self.delegate = d; [self show]; return [PMKPromise new:^(id fulfiller, id rejecter){ d->fulfiller = fulfiller; }]; }
它的promise方法很简单,仅仅就是创建并返回了一个PMKPromise对象,继续来看看promise的then方法,这个是最主要的方法,如果这个方法理解清楚了,这个框架就可以举一反三的大致理解清楚了。
- (PMKPromise *(^)(id))then { return ^(id block){ return self.thenOn(dispatch_get_main_queue(), block); }; }
我们看到then 他会调用thenOn方法,都返回的是一个block块。
- (PMKPromise *(^)(id))then 函数和调用形式[alert promise].then(^(){ NSLog(@"excute!");}) ,我们自己看看是不是感觉很奇怪,为什么then后面竟然带的是中括号,而我们通常在使用block的时候,一般都是带{}进行操作的,想想 [UIView animate:^{ }] ,是不是完全不一样,这里就涉及了一个block的用法了,就我来说看的和用的还是比较少的。区别如下:
1.通常,我们例如[UIView animate:^{ }] 都是在文件内部进行block的调用,而在客户端(调用的时候)来定义block块,我们通常用block块替换delegate的时候就是这么做得,也是大众的做法
2.此处,刚刚是反过来的,在内部定义block块,在外部调用,这样做得好处是在调用的时候就直接能执行。(想想promise是异步操作的一个库哦)
- (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 safely_call_block(block, result); }); }; } pending:^(id result, PMKPromise *next, dispatch_queue_t q, id block, PMKPromiseFulfiller resolve) { if (IsError(result)) return PMKResolve(next, result); dispatch_async(q, ^{ resolve(safely_call_block(block, result)); }); }]; }
thenOn方法又调用了- (id)resolved:(PMKResolveOnQueueBlock(^)(id result))mkresolvedCallback pending:(void(^)(id result, PMKPromise *next, dispatch_queue_t q, id block, PMKPromiseFulfiller resolver))mkpendingCallback 函数,一层层的调用,一层还没理解就下一次,无穷无尽了呢。不过没办法,只能接着往下看了。
- (id)resolved:(PMKResolveOnQueueBlock(^)(id result))mkresolvedCallback pending:(void(^)(id result, PMKPromise *next, dispatch_queue_t q, id block, PMKPromiseFulfiller resolver))mkpendingCallback { __block PMKResolveOnQueueBlock callBlock; __block id result; dispatch_sync(_promiseQueue, ^{ if ((result = _result)) return; callBlock = ^(dispatch_queue_t q, id block) { __block PMKPromise *next = nil; // 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]; 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); }
我们看到dispatch_barrier_sync函数,等待该队列前面的操作任务执行完成后才会执行这个block块。这至关重要的函数保证了then的同步执行,它的block块作用如下,创建了一个新的PMKPromise并且把then中带的block添加到_handlers, 这两个操作是关键步骤,至于这个函数中得大多其他代码都是进行递归解析then方法(别忘了,这是一个链式调用方法)。
resolver = ^(id o){ if (IsError(o)) reject(o); else fulfill(o); };
这里我们需要最后跟进一步,看看new 方法中得fulfill是什么:
id fulfiller = ^(id value){ if (PMKGetResult(this)) return NSLog(@"PromiseKit: Promise already resolved"); if (IsError(value)) @throw PMKE(@"You may not fulfill a Promise with an NSError"); PMKResolve(this, value); };
调用了PMKResolve函数,其他都是一些异常的处理。最后看看这个函数
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); }
执行所有的handler操作,并且设置result值。这里我们是否记得,在上面我们有把block存到handler中得。于是block就顺利的执行了。