如何使用Bolts Framework

刚才我从Facebook上看到这个关于IOS的Bolts框架的 公告 。

我可以看到这个主要概念:

Bolts中的第一个组件是“任务”,这使得复杂asynchronous代码的组织更容易pipe理

但是我没有得到这个。 我对Bolts framework感到困惑。 如何使用它( whether its related to web service or to JSON response parsing )。

他们提供了parsingSDK的ParseObject例子,但我不知道它,他们没有提供任何Xcode项目的例子。

Facebook就此提供了解释 。 但我无法弄清楚如何与我的项目进行整合。

他们提供的代码非常混乱:

 [[object saveAsync:obj] continueWithBlock:^id(BFTask *task) { if (task.isCancelled) { // the save was cancelled. } else if (task.error) { // the save failed. } else { // the object was saved successfully. SaveResult *saveResult = task.result; } return nil; }]; 

我们可以在这里下载bolt-framework。 任何人都可以解释更多关于这个?

更新: 在这里,我收到了关于螺栓的新问题的一些答案。

例子:假设你想从AssertLibrary中加载所有图像,并在加载时将所有图像的大小调整为标准大小,所以如果使用主线程,将会触发它。 在这个地方,如果用asynchronous操作的手段去,如何使用BFTask呢? 另一个例子 有一次,你试图调用10 webservice与asynchronous操作并行,你怎么能使用GCD与BFTask?

螺栓是伟大的。 同意现在的文档有点不专心。 虽然这是一个简单的例子:

 // the completion source is the *source* of the task... BFTaskCompletionSource *source = [BFTaskCompletionSource taskCompletionSource]; [self asynchronousMethodWithCompletion:^(id response, NSError *error) { // your task completed; inform the completion source, which handles // the *completion* of the task error ? [source setError:error] : [source setResult:entity]; }]; [source.task continueWithBlock:^id(BFTask *task) { // this will be executed after the asynchronous task completes... }]; 

我发现它对组完成(半伪代码)特别有用:

 NSMutableArray *tasks = @[].mutableCopy; loop { BFTaskCompletionSource *source = [BFTaskCompletionSource taskCompletionSource]; // ...make a task similar to above... [tasks addObject:source.task]; } // now the group completion: BFTask *groupTask = [BFTask taskForCompletionOfAllTasks:tasks.copy]; [source.task continueWithBlock:^id(BFTask *task) { // this will be executed after *all* the group tasks have completed }]; 

这是一个干净利落的方式,你可以用派遣组来做其他事情。 尽pipe如此,还有很多其他的function,比如在串行和并行等方面的sorting。

希望能帮助你开始。

这是一个应用程序的完整示例,可以支持多个参与者在处理networking请求和用户交互时更改数据。

我为自己设置了一个指导,当触摸与线程安全相关的任何服务时,使用链接到串行dispatch_queue_t的BFExecutor。

指出其他最佳做法将是有益的,谢谢!

 #import <Bolts/Bolts.h> dispatch_queue_t serialQueue; BFExecutor *serialExecutor; BFTask *maintask; int32_t key = 0; BOOL initialized = FALSE; @implementation yAppDelegate - (void)setKey:(int32_t)key_ { // Don't worry about success, just appending to outstanding tasks maintask = [maintask continueWithExecutor:serialExecutor withBlock:^id(BFTask *task) { BFTaskCompletionSource *source = [BFTaskCompletionSource taskCompletionSource]; key = key_; NSLog(@"set key to %d", key); [source setResult:nil]; if (initialized) { [self initialize]; } return source.task; }]; } - (BFTask *)downloadConfig { BFTaskCompletionSource *source = [BFTaskCompletionSource taskCompletionSource]; dispatch_async(serialQueue, ^{ NSLog(@"working on init config, key = %d...", key); // Trigger from a different queue double delayInSeconds = 1.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ [source setResult:nil]; }); }); return source.task; } - (BFTask *)initializeService { BFTaskCompletionSource *source = [BFTaskCompletionSource taskCompletionSource]; dispatch_async(serialQueue, ^{ NSLog(@"working on init service, key = %d...", key); // Trigger from a different queue double delayInSeconds = 1.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ [source setResult:nil]; }); // Set final state initialized = TRUE; }); return source.task; } - (void)initialize { int32_t oldKey = key; __block bool reinit = false; // Start by chaining it to whatever task is in flight without regard to success // Everything should use the serialQueue or serialExecutor for thread safety maintask = [[[maintask continueWithExecutor:serialExecutor withBlock:^id(BFTask *task) { if (oldKey != key) { NSLog(@"key out of date (%d != %d). reinitializing...", oldKey, key); reinit = true; return [BFTask cancelledTask]; } return [self downloadConfig]; }] continueWithExecutor:serialExecutor withSuccessBlock:^id(BFTask *task) { if (oldKey != key) { NSLog(@"key out of date (%d != %d). reinitializing...", oldKey, key); reinit = true; return [BFTask cancelledTask]; } return [self initializeService]; }] continueWithExecutor:serialExecutor withBlock:^id(BFTask *task) { if (oldKey != key) { NSLog(@"key out of date (%d != %d). reinitializing...", oldKey, key); reinit = true; } if (task.error || task.exception || task.isCancelled) { if (reinit) { [self initialize]; } return nil; } else { NSLog(@"initService completed = %d", key); return nil; } }]; } - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { serialQueue = dispatch_queue_create("serial", NULL); serialExecutor = [BFExecutor executorWithDispatchQueue:serialQueue]; // Start with an empty task so all tasks can be strung together without need to initialize maintask = [BFTask taskWithResult:nil]; // Everything related to changing service state should be contained with the serialQueue dispatch queue [self setKey:1]; [self initialize]; [self setKey:2]; [self setKey:3]; dispatch_async(dispatch_get_main_queue(), ^(void){ [self setKey:4]; }); dispatch_async(serialQueue, ^(void){ [self setKey:5]; }); [self setKey:6]; // Override point for customization after application launch. return YES; } @end 

结果如预期。 用键= 1尝试初始化,但是直到停止改变才有所不同。 然后服务在队列中初始化为key = 5,然后用key = 4重新初始化。

结果:

 set key to 1 key out of date (0 != 1). reinitializing... key out of date (0 != 1). reinitializing... set key to 2 set key to 3 set key to 6 set key to 5 key out of date (1 != 5). reinitializing... key out of date (1 != 5). reinitializing... working on init config, key = 5... working on init service, key = 5... initService completed = 5 set key to 4 working on init config, key = 4... working on init service, key = 4... initService completed = 4 

参考testing文件(即TaskTests.m)的例子。 Github上的例子是Parse特有的。

一般来看,为软件编写的testing在学习如何使用代码方面已经足够了。