美文网首页开发-使用技巧
iOS Bolts Framework 笔记

iOS Bolts Framework 笔记

作者: 路飞_Luck | 来源:发表于2018-07-07 15:43 被阅读132次

Bolts gitHub 连接地址

使用场景

当程序启动的时候,我们根据需要,向用户展示相关界面,比如升级弹窗,开启推送弹窗,广告弹窗,活动弹窗等等,但是如果不去有效的管理这些数据,就会导致数据冲突,界面混乱,从而给用户造成一些困扰,因此本文应运而生了。

解决整个 APP 运行时串行执行任务源码如下
串行执行任务

简介

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

BFTaskCompletionSource是 BFTask 的proxy object(代理对象),当 function 完成时设定 task.result,执行后则视为task complete,task.result 是 id 动态类型,可以将处理完后需要的结果设定到task.result,function 执行时导致的错误失败设定为task.error,如有执行出现例外,设定task.exception,如要取消task,调用[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 执行continueWithBlockcontinueWithSuccessBlock

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

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

  • Series:以串行方式回调task执行continueWithBlock
- (void)seriesTask {
    [[[self testAsync] continueWithBlock:^id _Nullable(BFTask * _Nonnull task) {
        BFTask *_task = [BFTask taskWithResult:nil];
        for (int i = 0; i < 3; i++) {
            task = [task continueWithBlock:^id _Nullable(BFTask * _Nonnull task) {
                return [self testAsync];
            }];
        }
        return _task;
    }] continueWithBlock:^id _Nullable(BFTask * _Nonnull task) {
        NSLog(@"tasks execute in series complete");
        return nil;
    }];
}
  • Parallel:将所有 task 塞进一个 array后丢给taskForCompletionOfAllTasks处理
- (void)parallelTask {
    [[[self testAsync] continueWithBlock:^id _Nullable(BFTask * _Nonnull task) {
        NSMutableArray *tasks = [NSMutableArray array];
        for (int i = 0; i < 3; i++) {
            [tasks addObject:[self testAsync]];
        }
        [tasks addObject:[self testAsync]];
        return [BFTask taskForCompletionOfAllTasks:tasks];
    }] continueWithBlock:^id _Nullable(BFTask * _Nonnull task) {
        NSLog(@"tasks execute in series complete");
        return nil;
    }];
}

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

  • immediateExecutor:是直接以GCD dispatch_once 执行

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

  • 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;
}
例子如下所示
测试准备

建立一个 object 对象并声明一个类方法返回 BFTask 对象
CSTask.h 文件

#import <Foundation/Foundation.h>
#import <Bolts/BFTaskCompletionSource.h>

@interface CSTask : NSObject

+ (BFTask *)taskWithResult:(NSString *)result;

@end

CSTask.m 实现文件

#import "CSTask.h"

@implementation CSTask

+ (BFTask *)taskWithResult:(NSString *)result {
    BFTaskCompletionSource *source = [BFTaskCompletionSource taskCompletionSource];
    source.result = result;
    return source.task;
}

@end

编写测试方法

- (BFTask *)testAsync {
    NSLog(@"testAsync");
    BFTaskCompletionSource *source = [BFTaskCompletionSource taskCompletionSource];
    source.result = @"test async complete";
    return source.task;
}

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

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

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

串行执行文件

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

执行结果

image.png
测试串行
- (void)seriesTask {
    [[[self testAsync] continueWithBlock:^id _Nullable(BFTask * _Nonnull task) {
        BFTask *_task = [BFTask taskWithResult:nil];
        for (int i = 0; i < 3; i++) {
            task = [task continueWithBlock:^id _Nullable(BFTask * _Nonnull task) {
                return [self testAsync1];
            }];
        }
        return _task;
    }] continueWithBlock:^id _Nullable(BFTask * _Nonnull task) {
        NSLog(@"tasks execute in series complete");
        NSLog(@"%@",task.result);
        return nil;
    }];
}

运行结果

image.png
测试并行
- (void)parallelTask {
    [[[self testAsync] continueWithBlock:^id _Nullable(BFTask * _Nonnull task) {
        NSMutableArray *tasks = [NSMutableArray array];
        for (int i = 0; i < 3; i++) {
            [tasks addObject:[self testAsync1]];
        }
        [tasks addObject:[self testAsync2]];
        return [BFTask taskForCompletionOfAllTasks:tasks];
    }] continueWithBlock:^id _Nullable(BFTask * _Nonnull task) {
        NSLog(@"tasks execute in series complete");
        NSLog(@"%@",task.result);
        return nil;
    }];
}

运行结果

image.png

本文参考 kakukeme 的Bolts framework iOS 笔记,非常感谢该作者。


项目连接地址

相关文章

网友评论

  • ai___believe:为啥我执行串形的,会先打印tasks execute in series complete,然后再去执行testAsync1 ?

本文标题:iOS Bolts Framework 笔记

本文链接:https://www.haomeiwen.com/subject/ymiwuftx.html