Bolts framework iOS 笔记

Bolts framework iOS 筆記
http://humanhighway.logdown.com/posts/179270-study-on-the-bolts

Bolts 是由 Facebook and Parse open source 的 Framework. 主要实现是为了解决 async callbacks 问题的 Promise Pattern. Promise / Future 在很多语言或 library 都有实现。 ( JQuery, AngularJS, Java, Dart ...etc )

虽说是 Framework 但用法并不难而且类数也不多。主要是以 BFTask, BFTaskCompletionSource, BFExector 这三个为主要。

假设我们要建立一个 testAsync function, 必须要在最后回传 BFTask , 建立 task 的方式则使用 BFTaskCompletionSource 的静态方法来建立 task 并设定相关参数。

(BFTask *)testAsync 
    NSLog(@"testAsync");
    BFTaskCompletionSource *source = [BFTaskCompletionSource taskCompletionSource];
    source.result = @"test async complete";
    return source.task;
    // or you can use taskWithResult
    // return BFTask taskWithResult: @"test async complete"];
}

BFTaskCompletionSource 是 BFTask 的 proxy object(代理对象)。当 function 完成时设定 task.result, 执行后则视为 task complete. task.result 是 id 动态型别,可以将处理完后需要的结果设定到 task.result. function 执行时导致错误失败设定 task.error, 如有执出现例外设定 task.exception, 如要取消 task 呼叫 [task cancel].

(task complete、task.result、task.error、task.exception、task cancel)

无论是 error/exception/cancel 执行完后皆视为 task complete. 另外, task 提供了一些方法来判断目前状况 isCancelled / isCompleted / error / exception. 也可以直接使用 [BFTask taskWithResult] / [BFTask taskWithError] / [BFTask taskWithException] / [BFTask cancelledTask] 静态方法直接建立 task 来做相关处理。

实现 Async function 之后, 可以一个接着一个将要调用的函数串起来称之为 Chain. 在每个函数回调的 task 执行 contineWithBlock / continueWithSuccessBlock

[[[[[self testAsync] continueWithBlock:^id(BFTask *task) {
    return [self testAsync1];
}] continueWithBlock:^id(BFTask *task) {
    return [self testAsync2];
}] continueWithBlock:^id(BFTask *task) {
    return [self testAsync3];
}] continueWithBlock:^id(BFTask *task) {
    NSLog(@"task in chain complete");
    return nil;
}];

另外还能以 Series / Parallel 的方式来执行 Task.

Series: 以串行方式回调 task 执行 continueWithBlock

[[[self testAsync] continueWithBlock:^id(BFTask *task) {
    BFTask *_task = [BFTask taskWithResult:nil];
    for (int i =0; i < 3; i++) {
        task = [task continueWithBlock:^id(BFTask *task) {
            return [self testAsync];
        }];
    }
    return _task;
}] continueWithBlock:^id(BFTask *task) {
    NSLog(@"tasks execute in series complete");
    return nil;
}];

Parallel : 将所有 task 塞进一个 array 后丢给 taskForCompletionOfAllTasks 作处理.

[[[self testAsync] continueWithBlock:^id(BFTask *task) {
        NSMutableArray *tasks = [NSMutableArray new];
        for (int i = 0 ; i < 3; i++) {
            [tasks addObject:[self testAsync]];
        }
        [tasks addObject:[self testAsync]];
        return [BFTask taskForCompletionOfAllTasks:tasks];
    }] continueWithBlock:^id(BFTask *task) {
        NSLog(@"tasks execute in parallel complete");
        return nil;
    }];

BFTask 主要是通过 BFExecutor 来执行, 默认是通过 [BFExecutor defaultExecutor] , 另外还有 immediateExecutor / mainThreadExecutor 可供使用,基于 GCD 实现。

  1. immediateExecutor : 是直接以 GCD dispatch_once 执行。

  2. mainThreadExecutor : 以 GCD dispatch_once 执行, 检查是否为 isMainThread, 如果不是则调用 dispatch_async(dispatch_get_main_queue(), block); 延后执行。

  3. defaultExecutor : 以 GCD dispatch_once 执行, 会检查 current thread 的 threadDictionary objectForKey:kBFTaskDepthKey 索取出的 depth 是否超过 20 个, 如果超过, 则 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block); 延后执行。否则会在当前 Thread 将 depth + 1, try-catch 执行完毕再 -1。

[[self testAsync] continueWithExecutor:[BFExecutor mainThreadExecutor] withBlock:^id(BFTask *task) {
            NSLog(@"task execute");
            return nil;
}

简单好上手, 应该很容易整合到现有的项目里。

相关资料

jQuery的deferred对象详解

使用 jQuery Deferred Object

Mine

测试准备


- (OSSTask *)testAsync
{
    NSLog(@"testAsync");
    
    OSSTaskCompletionSource *source = [OSSTaskCompletionSource taskCompletionSource];
    
   // [source setResult:@"test async complete"];
    source.result = @"test async complete";
    
    return source.task;
    
//    return [OSSTask taskWithResult:@"test async complete"];    
}

- (OSSTask *)testAsync1
{
    NSLog(@"testAsync1");
    
    return [OSSTask taskWithResult:@"test async1 complete"];
}

- (OSSTask *)testAsync2
{
    NSLog(@"testAsync2");
    
    return [OSSTask taskWithResult:@"test async2 complete"];
}

- (OSSTask *)testAsync3
{
    NSLog(@"testAsync3");
    
    return [OSSTask taskWithResult:@"test async3 complete"];
}

[[[[[self testAsync] continueWithBlock:^id _Nullable(OSSTask * _Nonnull task) {
    
    NSLog(@"%@", task.result);
    return [self testAsync1];
}] continueWithBlock:^id _Nullable(OSSTask * _Nonnull task) {
    
    NSLog(@"%@", task.result);
    return [self testAsync2];
}] continueWithBlock:^id _Nullable(OSSTask * _Nonnull task) {
    
    NSLog(@"%@", task.result);
    return [self testAsync3];
    
}] continueWithBlock:^id _Nullable(OSSTask * _Nonnull task) {
    
    NSLog(@"task in chain complete");
    
    NSLog(@"%@", task.result);
    
    return nil;
    
}];


2017-02-21 11:38:59.346161 Test-Project[847:195718] testAsync
2017-02-21 11:38:59.346771 Test-Project[847:195718] test async complete
2017-02-21 11:38:59.346845 Test-Project[847:195718] testAsync1
2017-02-21 11:38:59.347243 Test-Project[847:195718] test async1 complete
2017-02-21 11:38:59.347301 Test-Project[847:195718] testAsync2
2017-02-21 11:38:59.347696 Test-Project[847:195718] test async2 complete
2017-02-21 11:38:59.347862 Test-Project[847:195718] testAsync3
2017-02-21 11:38:59.348012 Test-Project[847:195718] task in chain complete
2017-02-21 11:38:59.348248 Test-Project[847:195718] test async3 complete

测试串行

/** Series: 以串行方式回调 task 执行 continueWithBlock */
[[[self testAsync] continueWithBlock:^id _Nullable(OSSTask * _Nonnull task) {
    
    OSSTask *_task = [OSSTask taskWithResult:nil];
    
    for (int i = 0; i < 3; i++) {
        
        NSLog(@"%@", task.result);
        task = [task continueWithBlock:^id _Nullable(OSSTask * _Nonnull task) {
            return [self testAsync1];
        }];
    }
    
    return _task;
    
}] continueWithBlock:^id _Nullable(OSSTask * _Nonnull task) {
    
    NSLog(@"tasks excute in series complete");
    
    NSLog(@"%@", task.result);
    
    return nil;
}];


2017-02-21 11:42:48.077688 Test-Project[855:196733] testAsync
2017-02-21 11:42:48.078335 Test-Project[855:196733] test async complete
2017-02-21 11:42:48.078422 Test-Project[855:196733] testAsync1
2017-02-21 11:42:48.078843 Test-Project[855:196733] test async1 complete
2017-02-21 11:42:48.078931 Test-Project[855:196733] testAsync1
2017-02-21 11:42:48.079150 Test-Project[855:196733] test async1 complete
2017-02-21 11:42:48.079291 Test-Project[855:196733] testAsync1
2017-02-21 11:42:48.079626 Test-Project[855:196733] tasks excute in series complete
2017-02-21 11:42:48.079918 Test-Project[855:196733] (null)


测试并行

/** Parallel : 将所有 task 塞进一个 array 后丢给 taskForCompletionOfAllTasks 作处理. */
[[[self testAsync] continueWithBlock:^id _Nullable(OSSTask * _Nonnull task) {
    
    NSMutableArray *tasks = [NSMutableArray new];
    
    for (int i = 0; i < 3; i ++ ) {
        [tasks addObject:[self testAsync1]];
    }
    
    [tasks addObject:[self testAsync2]];
    
    return [OSSTask taskForCompletionOfAllTasks:tasks];
    
}] continueWithBlock:^id _Nullable(OSSTask * _Nonnull task) {
  
    NSLog(@"tasks execute in parallel complete");
    
    NSLog(@"%@", task.result);
    
    return nil;
}];


2017-02-21 11:44:14.436728 Test-Project[858:197114] testAsync
2017-02-21 11:44:14.437287 Test-Project[858:197114] testAsync1
2017-02-21 11:44:14.437355 Test-Project[858:197114] testAsync1
2017-02-21 11:44:14.437401 Test-Project[858:197114] testAsync1
2017-02-21 11:44:14.437445 Test-Project[858:197114] testAsync2
2017-02-21 11:44:14.437735 Test-Project[858:197114] tasks execute in parallel complete
2017-02-21 11:44:14.437844 Test-Project[858:197114] (null)


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • NSThread 第一种:通过NSThread的对象方法 NSThread *thread = [[NSThrea...
    攻城狮GG阅读 789评论 0 3
  • Bolts 简介 自从Parse加盟Facebook后,他们发现很多细小的功能都分别在各自的sdk中实现了。于是他...
    卤蛋也幸福阅读 5,392评论 1 3
  • Managing Units of Work(管理工作单位) 调度块允许您直接配置队列中各个工作单元的属性。它们还...
    edison0428阅读 7,935评论 0 1
  • 第一篇第二篇大概是把下载图片缓存图片的这个逻辑走完了,里面涉及好多类。 罗列一下 UIView+WebCache ...
    充满活力的早晨阅读 734评论 0 1
  • 翻遍通讯录,找出号码,又放下的电话的那一刻,我发现,我竟是如此孤独。 这个通讯录里,只拨通了一个,除她以外,我发现...
    零零总总阅读 251评论 0 0