iOS-移动架构师

Bolts framework iOS 笔记

2017-02-17  本文已影响965人  kakukeme

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)


上一篇下一篇

猜你喜欢

热点阅读