2

這是設置。我有一個方法有一個完成塊,我想返回一個列表Item s。這些Item是從API中提取的。我希望每個提取都是異步發生的,但最終都會一起返回。如何在完成塊之前解析嵌套異步調用

這是我有:

public static func fetchItems(numberOfItems: Int, completion: ([Item]?, NSError?) ->()) -> Void { 
    var items: [Item] = [] 

    let group = dispatch_group_create() 

    for (var itemId = 0; itemId < numberOfItems; itemId++) { 

     dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) { 

      APIManager.fetchItemWithId(itemId) { 
       (item, error) in 

       guard let item = item else { 
        // handle error 
       } 

       print("Item \(itemId) downloaded") 

       items.append(item) 
      } 

     } 
    } 

    dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) { 
     completion(items, nil) 
    } 

} 

我的輸出端起來:

nil 
Item 0 downloaded 
Item 1 downloaded 
Item 2 downloaded 
etc 

雖然我派遣了Item小號異步的來電,電話本身具有內的另一個異步操作 - 在示例中由APIManager.fetchItemWithId說明。因此,最終,我的completion在API請求解析之前被擊中。

缺少什麼我在這裏?

回答

0

您的問題在於此異步調用APIManager。在該呼叫中阻止之前,您的分組已發送給分組。其實,所有組中的組塊完成之前。如果您可以選擇呼叫同步版本fetchItemWithId - 請在此處使用。如果沒有 - 使用dispatch_semaphore_t

dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) { 

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);  

    APIManager.fetchItemWithId(itemId) { 
     (item, error) in 
      guard let item = item else { 
       // handle error 
       dispatch_semaphore_signal(semaphore); 
      } 

      print("Item \(itemId) downloaded") 

      items.append(item) 

      dispatch_semaphore_signal(semaphore); 
     } 

    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); 
} 

隨意問,如果有什麼不清楚。或者,如果我誤解你的內涵

更新

我決定增加一些意見,使執行流程清楚,爲什麼發生的一切確實

for (var itemId = 0; itemId < numberOfItems; itemId++) { 

dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) { 
    //1 reach this point for "numberOfItems" times 
     APIManager.fetchItemWithId(itemId) { 
      (item, error) in 

      guard let item = item else { 
       // handle error 
      } 
      //4 we have no guarantee, when this point will be reached relatively to execution flow of "fetchItems" method. 
      //Actually, looks like it is dispatched to some low priority background queue. 
      //When it is first reached, "group" blocks have already been dispatched and successfully executed 
      print("Item \(itemId) downloaded") 

      items.append(item) 
     } 
    //2 previous block has been added to some queue. Reach this point for "numberOfItems" times 
    } 
    } 
    //3 reach this point. Most likely all group blocks have already been executed, so completion block is dispatched almost immediately 
    dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) { 
    completion(items, nil) 
} 
在我的例子
+0

我使用的方法'dispatch_semaphore_t ' - 所以我不確定你的意思是說使用它 –

+0

在你的例子中找不到信號量。你能告訴我 - 你在哪裏使用它? –

+0

你是對的,沒有信號量 - 我的不好 –

相關問題