Swift中如何通过DispatchGroup等待异步函数的Completion Block完成?
解决DispatchGroup等待异步Completion Block的问题
我明白你的困惑啦——原来的写法里,DispatchQueue.async(group:)只会等到你传入的外层闭包执行完毕(也就是调用完getDataFromUrl就结束了),但getDataFromUrl内部是异步的URLSession.dataTask,它的completion block要等网络请求完成才会执行,所以你的group.notify会提前触发,根本没等到两个网络请求真正完成。
核心解决思路:手动管理DispatchGroup的enter()和leave()
我们不能依赖async(group:)的自动分组管理,而是要手动标记异步任务的开始和结束:
- 在发起每个异步任务前调用
group.enter(),让DispatchGroup的任务计数+1 - 在
getDataFromUrl的completion block里调用group.leave(),让任务计数-1 - 当计数回到0时,
group.notify的闭包才会执行,确保两个网络请求都完成
修改后的完整代码示例
let queue = DispatchQueue(label: "com.company.app.queue", attributes: .concurrent) let group = DispatchGroup() // 第一个异步任务(func1) group.enter() // 标记任务启动 queue.async { // 替换成你的实际URL let url1 = URL(string: "https://example.com/data1")! getDataFromUrl(url: url1) { data, response, error in // 这里处理func1的结果,比如解析数据、错误处理 if let error = error { print("Func1 failed: \(error.localizedDescription)") } else if let data = data { print("Func1 got data: \(data.count) bytes") } group.leave() // 标记任务完成 } } // 第二个异步任务(func2) group.enter() queue.async { let url2 = URL(string: "https://example.com/data2")! getDataFromUrl(url: url2) { data, response, error in // 处理func2的结果 if let error = error { print("Func2 failed: \(error.localizedDescription)") } else if let data = data { print("Func2 got data: \(data.count) bytes") } group.leave() } } // 等待所有任务完成后执行后续逻辑 group.notify(queue: DispatchQueue.main) { // 通常用主队列做UI更新,也可以用你自己的queue print("#3 finished") }
关键注意事项
- 必须保证
enter()和leave()一一对应:如果少写了leave(),DispatchGroup的计数永远不会回到0,notify永远不会触发;如果多写了leave(),会导致计数负数,程序可能崩溃。 group.leave()是线程安全的:不管getDataFromUrl的completion block在哪个队列执行,直接调用leave()就行,不需要额外切换队列。- 如果需要在completion里更新UI,记得在completion内部切换到主队列(比如
DispatchQueue.main.async { ... }),这和DispatchGroup的同步逻辑是分开的。
内容的提问来源于stack exchange,提问作者adi pslr
相关产品推荐
相关产品推荐

