在DispatchQueue.main.async中调用函数的Swift代码技术咨询
问题分析与修复方案
从你的代码来看,你想要利用DispatchGroup等待所有uploadPhoto任务完成后输出"done",但当前的写法存在两个关键问题:
- DispatchGroup的
enter()/leave()不匹配:你只调用了一次group.enter(),但循环里会触发多个uploadPhoto任务,每个异步任务都需要单独的enter()来标记任务开始。 leave()调用时机错误:你在主队列的循环结束后立刻调用group.leave(),但uploadPhoto里的网络请求是异步执行的——这意味着leave()会在所有上传任务完成前就被调用,导致group.notify提前触发,无法正确等待所有任务结束。
修复后的代码示例
首先调整DispatchGroup的使用逻辑,确保每个异步上传任务都对应一对enter()/leave():
let group = DispatchGroup() // 主队列是串行队列,循环可以直接执行,无需额外async包裹(如果循环耗时可移到后台队列) for i in 0 ... (Global.selectedIcons.count - 1) { group.enter() // 每个上传任务开始前标记enter if self.albumorphoto == 1 { self.detector = i == 0 ? 1 : 2 } else { self.detector = 0 // 可根据实际需求设置默认值 } self.uploadPhoto { // 在上传任务的异步回调里标记leave group.leave() } } group.notify(queue: .main) { print("done") } // 改造uploadPhoto函数,添加完成回调 func uploadPhoto(completion: @escaping () -> Void) { guard let url = URL(string: "你的上传地址") else { completion() return } var request = URLRequest(url: url) // 配置request(比如设置HTTPMethod、请求体、Header等) let task = URLSession.shared.dataTask(with: request) { data, response, error in // 处理上传结果 defer { // 无论成功失败,都调用completion触发leave,保证Group计数正确 completion() } if let error = error { print("上传失败: \(error.localizedDescription)") return } // 处理上传成功后的逻辑(比如解析响应数据) print("第\(self.detector)类资源上传成功") } task.resume() }
额外说明
- 如果你的
uploadPhoto原本没有完成回调,必须添加一个闭参来通知外部任务完成——这是确保DispatchGroup能正确跟踪异步任务的核心。 - 如果循环本身耗时(比如需要处理大量本地图片压缩),建议把循环放到后台队列执行,避免阻塞主队列影响UI响应:
DispatchQueue.global().async { let group = DispatchGroup() // 循环逻辑... group.notify(queue: .main) { print("done") } }
内容的提问来源于stack exchange,提问作者catcatcat
相关产品推荐
相关产品推荐

