GCD:异步等待条件

时间:2013-10-05 04:35:59

标签: ios asynchronous grand-central-dispatch

在我的iOS应用中,我想在更新UI之前等待条件成为现实。 我这样做:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
  while (!condition) NSLog("waiting for the condition");
  dispatch_sync(dispatch_get_main_queue, ^{
    //update the UI here
  });
});

上面的代码工作正常,但我想问一下,使用 while 循环来做等待工作是否好,如果有更好的方法。 谢谢!

---更新

条件实际上是4个BOOL变量的组合。每个变量都与来自服务器的内容请求相关联。我正在使用AFNetworking框架。在4个请求中的每个请求的完成块中,我将关联的BOOL变量设置为YES。 所以,实际的while循环是这样的:

while (!([MyRequest request1].isFinished && [MyRequest request2].isFinished && [MyRequest request3].isFinished && [MyRequest request4].isFinished)) NSLog("waiting for the condition");

2 个答案:

答案 0 :(得分:6)

在修订后的问题中,您可能希望依赖四个AFNetworking操作。这要容易得多。您可能只需添加一个新操作,并使其依赖于其他四个操作:

NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        // update UI
    }];
}];

[operation addDependency:requestOneOperation];
[operation addDependency:requestTwoOperation];
[operation addDependency:requestThreeOperation];
[operation addDependency:requestFourOperation];

[queue addOperation:operation];

addDependency机制基本上为您执行其他四个操作中isFinished的KVO。这是使用基于NSOperation的框架(如AFNetworking)的乐趣之一。这种依赖很容易做到。


原始答案:

如果你必须这样做,你可能会使用信号量,例如,你创建一个信号量:

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

您的异步块等待:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
    dispatch_semaphore_wait(semaphore);
    dispatch_sync(dispatch_get_main_queue, ^{
        //update the UI here
    });
});

当满足条件时,否则将设置此条件标志的代码将改为:

dispatch_semaphore_signal(semaphore);

话虽如此,除非绝对必要,否则我宁愿看不到这样的队列(甚至是并发全局队列)。如果其他代码可以发出信号量信号,我不确定为什么它不能只是启动UI更新本身。如果我确实使用了这种信号量技术,至少我会在我自己创建的队列中进行这种等待过程,而不是全局队列。


您可以在许多情况下使用的另一种方法,我可能更喜欢使用key value observing

例如,我可以观察到名为someProperty的对象的obj属性的更改,如下所示:

[obj addObserver:self forKeyPath:@"someProperty" options:NSKeyValueObservingOptionNew context:NULL];

然后我会实施observeValueForKeyPath

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"someProperty"])
    {
        NSLog(@"update UI here");
    }
}

每当更新someProperty对象的obj属性时,都会调用observeValueForKeyPath方法。

仅供参考,我还要确保在此对象发布之前,我将移除obj的观察者:

[obj removeObserver:self forKeyPath:@"someProperty"];

显然,这假设somePropertyKey Value Coding Compliant。但如果是的话,这是一项很棒的技术。

答案 1 :(得分:0)

虽然这里的一般模式是正确的(Apple将其称为“调用回调”),但while(!condition)位也称为“自旋锁”,绝对不是等待a的最佳方式条件。请考虑改为使用NSTimerNSRunLoop