使用场景
当程序启动的时候,我们根据需要,向用户展示相关界面,比如升级弹窗,开启推送弹窗,广告弹窗,活动弹窗等等,但是如果不去有效的管理这些数据,就会导致数据冲突,界面混乱,从而给用户造成一些困扰,因此本文应运而生了。
解决整个 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 执行continueWithBlock
或continueWithSuccessBlock
。
[[[[[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;
}];
}
执行结果
![](https://img.haomeiwen.com/i1653926/c053c9b6d89e436e.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;
}];
}
运行结果
![](https://img.haomeiwen.com/i1653926/8e8b85f4309bb35a.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;
}];
}
运行结果
![](https://img.haomeiwen.com/i1653926/c088cf62821b44e2.png)
本文参考 kakukeme 的Bolts framework iOS 笔记,非常感谢该作者。
网友评论