2013-10-05 102 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部分而成爲自旋鎖嗎? –