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

你是对的,没有信号量 - 我的不好 –

相关问题