2012-03-06 74 views
6

我正在創建一個從數據庫中獲取一組結果的應用程序 - 我使用MBProgressHUD來顯示查詢的動畫進度。我使用的方法在另一個線程中執行方法時調用動畫,一旦完成,它就隱藏動畫。我的問題是,打完電話後:iOS中的多線程 - 如何強制線程等待條件?

[HUD showWhileExecuting:@selector(getResults) onTarget:self withObject:nil animated:YES]; 

我想,如果沒有結果,顯示一個警告,說明這一點,如果有,加載下一個視圖。到目前爲止,我有這樣的代碼:

[HUD showWhileExecuting:@selector(getResults) onTarget:self withObject:nil animated:YES]; 

if(self.thereAreEvents) { 
    [self performSegueWithIdentifier:@"searchResults" sender:self]; 
} else { 
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"No results" message:@"Sorry, there are no results for your search. Please try again." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; 
    [alert show]; 
    [alert release]; 
} 

self.thereAreEvents被設定在getResults方法結束。但是,由於該方法在另一個線程中被調用,因此即使數據庫中存在事件,該行的執行也會繼續並顯示警報。

所以,從這裏開始,我有兩個問題:什麼是在iOS中實現等待信號機制的最簡單方法,以及在iOS中實現這種機制的最有效方式是什麼?

謝謝!

回答

2

你也可以考慮一個NSConditionLock

所以它會是在線程1是這樣的:

[conditionLock lockWhenCondition:kConditionOkayToProceed]; 
[conditionLock unlockWithCondition:kConditionGettingResults]; 

[HUD show...] 

[conditionLock lockWhenCondition:kConditionResultsFetched]; 
[conditionLock unlockWithCondition:kConditionOkayToProceed]; 

而在HUD:

- (void)show... 
{ 
    [conditionLock lockWhenCondition:kConditionGettingResults]; 

    // stuff here 

    [conditionLock unlockWithCondition:kConditionResultsFetched]; 
} 

雖然一個更好的解決辦法是通過一個塊或目標/選擇器在選取結果時將執行的HUD。

編輯:所以你會最終像代碼:

[HUD showWhileExecuting:@selector(getResults) 
    onTarget:self 
    withObject:nil 
    animated:YES 
    performWhenFinished: 
    ^{ 
     if(self.thereAreEvents) { 
      [self performSegueWithIdentifier:@"searchResults" sender:self]; 
     } else { 
      UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"No results" message:@"Sorry, there are no results for your search. Please try again." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; 
      [alert show]; 
      [alert release]; 
     } 
     }]; 

而在HUD:

- (void)showWhile... performWhenFinished:(dispatch_block_t)block 
{ 
    // all the other stuff you were going to do here, then 
    // eventually... 

    // if no guarantees, maybe just: 
    block(); 

    // otherwise, if promised to dispatch to the main queue: 
    dispatch_async(dispatch_get_main_queue(), block); 
} 

採用具有額外的智能HUD採取dispatch_block_t作爲最後一個參數和在結果存在時調用它(無論是否保證調度回到主線程或其他方式)。

+0

。我仍然需要學習iOS編程。我會看看那個。謝謝! – KerrM 2012-03-06 19:46:19

+0

'通過一個區塊'模式是相對較新的,但似乎是蘋果公司在iOS 5中的新API中領導的方向。 'TWRequest'或'ACAccountStore'。實際上,按照似乎正在出現的慣例,使用'completionHandler:'而不是'performWhenFinished:'來提供塊可能會更好。 – Tommy 2012-03-06 19:55:00

0

不知道這是否是最好的辦法,但我會嘗試使用while循環來觀察一些布爾類型,如[NSThread sleepForTimeInterval:1];在循環內。

也許設置超時。

0

這是你的方式: Concurrency Programming Guide

另外:Synchronization

更加犀利:Using Locks。我認爲最後一個可以提供最好的幫助。

另一種簡單的方法,這是不好的,但工程

NSAssert(![NSThread isMainThread], @"Do not run on MAIN thread"); 
while (yourCondition) { [NSThread sleepForTimeInterval:0.2]; } 
11

您可以使用一個忙等循環的快速和骯髒的解決方案:

__block BOOL finished = NO; 
dispatch_async(/* global queue */, ^{ 
    // … 
    finished = YES; 
}); 
while (!finished) /* waiting */; 

在「真實」的代碼,最好使用信號量:

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 
dispatch_async(/* global queue */, ^{ 
    // … 
    dispatch_semaphore_signal(semaphore); 
}); 
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); 
dispatch_release(sempahore); 

這比忙循環更好,因爲被阻塞的線程不會佔用CPU時間。

最好的解決方案是阻止並重新設計您的代碼以異步工作。在你的情況下,你應該顯示一個微調並開始下載數據。數據完成下載後,您應該收到異步回調(通過塊或目標/操作回調)並顯示結果或顯示錯誤警報。在這種情況下,使用繁忙循環或信號量阻塞是一個窮人的解決方案。

+0

感謝您的答覆。誠實地說,在編程iOS時我完全失去了,但我會研究異步回調。再次感謝! – KerrM 2012-03-06 19:47:57

+0

只是一個評論,dispatch_release不需要,因爲我看到iOS6 – 2016-03-11 19:36:55

0

可以使用dispatch_time_t作爲..

double delayInSeconds = 2.0; 
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); 
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 
    <#code to be executed on the main queue after delay#> 
});