Ios 如何在完成块之前解析嵌套异步调用

Ios 如何在完成块之前解析嵌套异步调用,ios,multithreading,swift,grand-central-dispatch,dispatch-async,Ios,Multithreading,Swift,Grand Central Dispatch,Dispatch Async,这是设置。我有一个方法,它有一个完成块,我想在其中返回项的列表。这些项是从API获取的。我希望每个回迁都是异步进行的,但最终会一起返回项 以下是我所拥有的: public static func fetchItems(numberOfItems: Int, completion: ([Item]?, NSError?) -> ()) -> Void { var items: [Item] = [] let group = dispatch_group_create(

这是设置。我有一个方法,它有一个完成块,我想在其中返回
项的列表。这些
是从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)
    }

}
当我异步调度对
的调用时,调用本身内部有另一个异步操作-如示例中的
apimager.fetchItemWithId
所示。因此,最终,我的
完成
会在API请求解决之前被命中


我在这里遗漏了什么?

您的问题在于对
apimager
的异步调用。您的块,分派到组在该调用中的块完成之前完成。实际上,组中的所有块在它之前完成。如果您可以选择调用同步版本的
fetchItemWithId
,请在此处使用它。如果没有-使用
调度信号灯\u 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)
}
for(var-itemId=0;itemId
在我的示例中,我使用的是
dispatch\u semaphore\u t
——因此我不确定您所说的使用它的确切含义在您的示例中找不到任何信号量。你能告诉我-你在哪里用它吗?很高兴我能帮忙。看看最新的答案——也许它会让事情变得更糟clear@HarlanKellaway如果你能记下我的答案,如果你认为值得,请投我一票,我将不胜感激。毕竟,我尽了最大努力,这对你有帮助=)
 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)
}