14

我試圖以同步的iOS5以下代碼:我應該如何使用GCD dispatch_barrier_async iOS中(之前似乎沒有和其他後塊來執行)

  1. 對象具有使一個HTTP請求的方法從中 得到一些數據,包括圖片網址
  2. 一旦數據到達時,文本數據被用來填充 CoreData模型
  3. 在同一時間,第二個線程分派異步下載 圖片;此線程將通過KVO發送信號給viewController,此時 圖像已被緩存並可在CoreData模型中使用。
  4. 由於圖片下載需要一段時間,我們馬上將 的CoreData對象具有除圖片外的所有屬性給 作爲調用者。
  5. 另外,當第二個線程完成下載時,可以保存CoreData型號 。

這是(簡化)代碼:

- (void)insideSomeMethod 
{ 
    [SomeHTTPRequest withCompletionHandler: 
    ^(id retrievedData) 
    { 
     if(!retrievedData) 
     { 
      handler(nil); 
     } 

     // Populate CoreData model with retrieved Data... 

     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 
      NSURL* userImageURL = [NSURL URLWithString:[retrievedData valueForKey:@"imageURL"]]; 
      aCoreDataNSManagedObject.profileImage = [NSData dataWithContentsOfURL:userImageURL]; 
     }); 

     handler(aCoreDataNSManagedObject); 
     [self shouldCommitChangesToModel]; 
    }]; 
} 

- (void)shouldCommitChangesToModel 
{ 
    dispatch_barrier_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 
     NSError *error = nil; 
     if(![managedObjectContext save:&error]) 
     { 
      // Handle error 
     } 
    }); 
} 

但是發生了什麼事情是,阻擋基於保存塊的圖像加載塊之前總是執行。也就是說,

dispatch_barrier_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 
      NSError *error = nil; 
      if(![managedObjectContext save:&error]) 
      { 
       // Handle error 
      } 
     }); 

前執行:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 
       NSURL* userImageURL = [NSURL URLWithString:[retrievedData valueForKey:@"imageURL"]]; 
       aCoreDataNSManagedObject.profileImage = [NSData dataWithContentsOfURL:userImageURL]; 
      }); 

所以,很顯然,我不是真的調度圖像加載塊障礙之前,或阻擋會等到圖像加載塊完成在執行之前(這是我的意圖)。

我在做什麼錯?如何確保圖像加載塊在阻擋塊之前排隊?

回答

27

乍一看問題可能是您正在調度全局併發隊列中的障礙塊。您只能在自己的自定義併發隊列中使用屏障塊。根據dispatch_barrier_async上的GCD文檔,如果將塊分派給全局隊列,它將表現得像正常的dispatch_async調用。

邁克灰分對GCD屏障阻擋了良好的博客文章:http://www.mikeash.com/pyblog/friday-qa-2011-10-14-whats-new-in-gcd.html

好運

牛逼

+0

我自己想了好幾次,但之後,蘋果公司的文檔沒有說明在iOS中我們不能真正創建自己的隊列嗎?所以如果我「創造」一個,我實際上只是獲得一個全球化之一的別名? – SaldaVonSchwartz

+0

我相信,從ios5開始,您可以創建您的調度隊列。 – timthetoolman

+0

是的,我剛剛嘗試過它,現在它工作。我會發誓我讀了我們無法創建自己的或創建它們僅僅返回全局的一個,這就是爲什麼我只是在上面的代碼中明確地使用了全局的全局。 – SaldaVonSchwartz

3

您需要創建自己的隊列,並沒有分派到其全球隊列爲每ADC文檔

您指定的隊列應該是一個併發隊列,您使用dispatch_queue_create函數自己創建 ñ。如果 傳遞給此函數的隊列是串行隊列或全局併發隊列之一,則此函數的行爲與dispatch_async 函數的行爲相同。

from https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html#//apple_ref/c/func/dispatch_barrier_async

你可以創建大量自己的GCD隊列。 gcd隊列非常小,你可以創建他們噸沒有問題。當你完成它們時你只需要釋放它們。

+0

只是一個頭。如果您的部署目標是iOS6 +並且您使用的是ARC,則不需要釋放隊列(您不能)。 ARC會爲你做到這一點! –

0

對於您似乎試圖解決的問題,dispatch_barrier_async可能不是最佳解決方案。 查看併發編程指南的Migrating Away From Threads部分。只需在自己的串行隊列上使用dispatch_sync即可解決您的同步問題。 或者,您可以使用NSOperation和NSOperationQueue。與GCD不同,NSOperation允許您輕鬆管理依賴關係(您可以使用GCD執行此操作,但它可能會變得很難)。

相關問題