【问题标题】:How to use Bolts Framework[Facebook+Parse]如何使用 Bolts 框架[Facebook+Parse]
【发布时间】:2014-02-26 14:20:15
【问题描述】:

刚才我从 Facebook 看到 this announcement 关于 IOS 的 Bolts 框架

我可以将其视为主要概念:

Bolts 中的第一个组件是“任务”,它使复杂异步代码的组织更易于管理

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

他们提供了带有解析 SDK 的 ParseObject 的示例,但我不知道,他们没有提供任何 Xcode 项目的示例。

Facebook 对此提供了explanation。但我不知道如何与我的项目集成。

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

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

我们可以下载bolts-frameworkhere。谁能详细解释一下?

更新:Here我收到了一些关于螺栓新问题的答案。

示例: 假设您要从 AssertLibrary 加载所有图像,并在加载时将所有图像调整为标准尺寸,因此如果使用主线程会触发。在这个地方,如果你使用异步操作的方式,如何使用 BFTask 呢?另一个前。有一次,你试图用异步操作并行调用 10 个 web 服务,你怎么能将 GCD 与 BFTask 一起使用?

【问题讨论】:

  • 抱歉,我自己找不到太多信息,也没有尝试将它与我自己的项目集成。

标签: ios facebook parse-platform bolts-framework


【解决方案1】:

螺栓很棒。同意文档现在有点不集中。不过,这里有一个简单的例子:

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

这是一种更简洁的方式来执行您原本可以对调度组执行的操作。但是,在串行和并行任务排序等方面,它还有很多其他功能。

希望能帮助您入门。

【讨论】:

  • 感谢@itsthejb 看到这个链接stackoverflow.com/questions/21599172/…。你的答案和这个一样。请看那些评论。并请解释它与异步操作有何关系?
  • Bolts 旨在包装/封装任何类型的异步任务。您需要做的就是在操作完成时向任务完成源发送消息。我们的想法是以这种方式包装您的任何操作。
  • 是的,我认识人。但是上面的任务哪里可以找到异步任务呢?您在异步任务完成后而不是在异步任务期间处理了 BFTask?我对吗?我想知道,BFTask如何异步任务,尤其是BFTask在哪里锁定和解锁资源?
  • 我会给你+1的方法吗?如果你没有明白我的意思,请给 cmets。或者对此进行更多研究并帮助我。谢谢你:)
  • 我认为你误解了框架的目的。 Bolts 对编写异步操作没有任何帮助。它旨在使用通用接口封装和排序操作
【解决方案2】:

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

我已经为自己设置了一个指南,以便在接触与线程安全相关的任何服务时使用链接到串行 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

结果符合预期。尝试使用 key = 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

【讨论】:

    【解决方案3】:

    有关示例,请参阅测试文件(即 TaskTests.m)。 Github 上的示例是 Parse 特有的。

    一般来说,查看为软件编写的测试就足以了解如何使用代码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多