我正在查看Ray Wenderlich教程,介紹使用分派隊列在一組任務完成時得到通知。 http://www.raywenderlich.com/63338/grand-central-dispatch-in-depth-part-2dispatch_group_wait()dispatch_group_create()和dispatch_group_enter()從不同的隊列中調用時的行爲需要說明
在「代碼工作」下顯示的第一個代碼直接來自教程。警報視圖(最終完成塊)在所有3次下載完成後執行。
我試着玩弄它,並在「不工作的代碼」中將異步向下移動,以查看dispatch_group_create()和dispatch_group_enter()發生在不同隊列中會發生什麼。在這種情況下,dispatch_group_enter()似乎沒有註冊,因爲即使在所有下載完成之前,dispatch_group_wait()立即完成並且警報視圖(最終完成塊)被執行。
有人可以解釋什麼發生在第二個案件? (這只是爲了我的理解dispatch組是如何工作的,我意識到這最好是將整個函數放在全局併發隊列中以避免阻塞主線程)。
的作品- (void)downloadPhotosWithCompletionBlock:(BatchPhotoDownloadingCompletionBlock)completionBlock
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),^{
__block NSError *error;
dispatch_group_t downloadGroup = dispatch_group_create();
for (NSInteger i = 0; i < 3; i++)
{
NSURL *url;
switch (i) {
case 0:
url = [NSURL URLWithString:kOverlyAttachedGirlfriendURLString];
break;
case 1:
url = [NSURL URLWithString:kSuccessKidURLString];
break;
case 2:
url = [NSURL URLWithString:kLotsOfFacesURLString];
break;
default:
break;
}
dispatch_group_enter(downloadGroup);
__block Photo *photo = [[Photo alloc] initwithURL:url
withCompletionBlock:^(UIImage *image, NSError *_error) {
if (_error) {
error = _error;
}
NSLog(@"Finished completion block for photo alloc for URL %@ and photo is %@",url,photo) ;
dispatch_group_leave(downloadGroup);
}];
[[PhotoManager sharedManager] addPhoto:photo];
NSLog(@"Finished adding photo to shared manager for URL %@ and photo is %@",url,photo) ;
}
dispatch_group_wait(downloadGroup, DISPATCH_TIME_FOREVER); // 5
dispatch_async(dispatch_get_main_queue(), ^{
if (completionBlock) {
NSLog(@"Executing completion block after download group complete") ;
completionBlock(error);
}
}) ;
}) ;
}
編輯的代碼
代碼,不具有額外的NSLog語句
代碼的工作,不工作
- (void)downloadPhotosWithCompletionBlock:(BatchPhotoDownloadingCompletionBlock)completionBlock
{
__block NSError *error;
dispatch_group_t downloadGroup = dispatch_group_create();
for (NSInteger i = 0; i < 3; i++)
{
NSURL *url;
switch (i) {
case 0:
url = [NSURL URLWithString:kOverlyAttachedGirlfriendURLString];
break;
case 1:
url = [NSURL URLWithString:kSuccessKidURLString];
break;
case 2:
url = [NSURL URLWithString:kLotsOfFacesURLString];
break;
default:
break;
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),^{
dispatch_group_enter(downloadGroup);
NSLog(@"Enetered group for URL %@",url) ;
__block Photo *photo = [[Photo alloc] initwithURL:url
withCompletionBlock:^(UIImage *image, NSError *_error) {
if (_error) {
error = _error;
}
NSLog(@"Finished completion block for photo alloc for URL %@ and photo is %@",url,photo) ;
dispatch_group_leave(downloadGroup);
}];
[[PhotoManager sharedManager] addPhoto:photo];
NSLog(@"Finished adding photo to shared manager for URL %@ and photo is %@",url,photo) ;
}) ;
}
NSLog(@"Executing wait statement") ;
dispatch_group_wait(downloadGroup, DISPATCH_TIME_FOREVER); // 5
dispatch_async(dispatch_get_main_queue(), ^{
if (completionBlock) {
NSLog(@"Executing completion block after download group complete") ;
completionBlock(error);
}
}) ;
}
謝謝,這是有道理的。請參閱上面的修改。我看到在「dispatch_wait」之前的NSLog語句之前執行「group_enter」之後的NSLog語句。這似乎指出了除上述解釋以外的一些根本原因。我應該使用斷點進行調試嗎? Xcode中的NSLog輸出是2016-02-21 21:37:01.155 GooglyPuff [393:136916]這是你的外在聲音:我是在內部聲音之前還是之後打印? 2016-02-21 21:37:05.319 GooglyPuff [393:136937]網址爲http://i.imgur.com/UvqEgCv.png 2016-02-21 21:37:05.319 GooglyPuff [393:136916 ]執行等待語句 –
剛剛執行了斷點。首先執行1st dispatch_group_enter,然後dispatch_group_wait,然後剩下兩個dispatch_group_enter。在dispatch_group_wait調用期間dispatch_group_enter的執行和狀態更改被反映之間是否存在延遲?添加最小延遲([NSThread sleepForTimeInterval:0.001];)將消除競態條件,並且事情按照預期的順序發生。 –
在您的問題中輸入一個沒有斷點的運行輸出。我沒有按照上面評論中的內容。增加延遲可能會減少競爭條件的窗口,但不一定會消除它。競爭條件是程序邏輯的問題,而不僅僅是執行的變幻莫測(比如系統是否忙或調度器打嗝等等)。 –