1

在我的 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");
4

2 回答 2

7

在修订后的问题中,听起来您有四个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];

该机制本质上为您执行其他四个操作中的每一个的addDependencyKVO 。isFinished这是使用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 更新。如果我确实使用了这种信号量技术,至少我会让这个等待过程发生在我自己创建的队列上,而不是全局队列上。


您可以在许多情况下使用的另一种方法,我可能更喜欢使用键值观察

例如,我可以观察到someProperty一个对象的 they 属性的变化,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。但如果是这样,这是一项很棒的技术。

于 2013-10-05T04:43:19.030 回答
0

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

于 2013-10-05T04:43:06.893 回答