2013-10-05 105 views
1

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

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 
    }); 
}); 

上面的代码工作得很好,但我想问一下,如果使用循环来等待工作是好还是不好,如果有什么更好的办法。 谢谢!

---更新

该条件实际上是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"); 
+0

你能给我们一个不太抽象的例子吗?这个“条件”究竟是你想要检查的?不同的场景提出了不同的方法(信号量,KVO,重复'NSTimer','CADisplayLink'等)。但是这种“while”循环方法通常是不可取的。 – Rob

+0

我只是想简化问题,但这使我的问题变得更糟。只需更新细节,@Rob。 –

+0

这非常有帮助。在这种情况下,我只需创建一个新操作,并使其依赖于其他四个请求操作。看修改后的答案。 (仅供参考,这对四项操作的'isFinished'属性有效执行KVO。) – Rob

回答

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志愿。这是使用基于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 
    }); 
}); 

而且当条件满足时,代码会另外设置该con dition标志会,而不是:

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"); 
    } 
} 

只要我的obj对象的someProperty属性更新,我的observeValueForKeyPath方法就会被调用。

仅供参考,我也想确保该对象被释放之前,我想删除的obj观察员:

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

显然,这种假设somePropertyKey Value Coding Compliant。但如果是这样,这是一个伟大的技术。

+0

假设条件得到更新,我无法访问的地方,所以我不能用dispatch_semaphore_signal发送信号。 –

+0

是最后一个语句中的'队列'[queue addOperation:operation]; [NSOperationQueue mainQueue]? –

+0

@ThanhPham绝对不是主队列。这是您创建的一个“队列”,例如'NSOperationQueue * queue = [[NSOperationQueue alloc] init];'。可以是您添加其他四个请求的同一队列。任何你想要的。 – Rob

0

虽然这里的一般模式是正确的(苹果是指它作为“电话回拨”),该while(!condition)位也被称为“自旋锁”,并且绝对不是等待病情的最佳方式。请考虑使用NSTimerNSRunLoop代替。

+0

是这样的吗? while(!condition && [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]); 所以while语句仍然存在,但是我猜这不会因为NSRunLoop部分而成为自旋锁吗? –