这是设置。我有一个方法,它有一个完成 block ,我想在其中返回 Item
的列表。这些 Item
是从 API 中获取的。我想让每个提取都异步发生,但最终会一起返回 Item
。
这是我所拥有的:
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
说明。因此,最终,我的完成
在 API 请求解析之前被命中。
我在这里错过了什么?
最佳答案
您的问题在于对 APIManager
的异步调用。您的 block ,在该调用中的 block 之前分派(dispatch)给组完成。实际上,组中的所有 block 在它之前完成。如果您可以选择调用 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)
}
关于ios - 如何在完成 block 之前解决嵌套的异步调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32936350/