如何用GCD并行执行Swift数组中图片URL的下载任务?
如何在Swift中并行下载多张图片并等待全部完成?
没问题,我来帮你搞定这个并行下载的需求!不用修改你的URL数组,借助GCD的DispatchGroup就能轻松实现并行执行+等待全部完成的逻辑,下面直接上方案:
基础实现(假设downloadImage(_:)是同步方法)
let urls:[String] = [ "http://acme.com/one.jpeg", "http://acme.com/two.jpeg", "http://acme.com/three.jpeg", ] // 创建调度组,用来跟踪所有异步任务的完成状态 let downloadGroup = DispatchGroup() for url in urls { // 每启动一个任务前,标记"进入组" downloadGroup.enter() // 在全局并发队列执行下载任务,自动实现并行 DispatchQueue.global().async { defer { // 用defer确保任务无论成功/失败,最终都会标记"离开组" downloadGroup.leave() } downloadImage(url) } } // 等待所有任务完成后,在指定队列执行后续操作(这里用主队列,适合后续更新UI) downloadGroup.notify(queue: DispatchQueue.main) { print("all images downloaded.") }
关键逻辑拆解
- DispatchGroup的核心机制:
enter()和leave()必须成对出现,调度组会统计未完成的任务数量,当数量归0时就会触发后续的notify回调。 - 全局并发队列的作用:
DispatchQueue.global()是系统维护的线程池,会自动把不同的下载任务分配到不同线程执行,天然实现并行效果。 notify方法的意义:它不会阻塞当前线程,而是在所有任务完成后,在你指定的队列(比如主队列)执行闭包,保证打印语句只会在全部下载完成后触发。
如果downloadImage(_:)是异步方法(带Completion Handler)
如果你的downloadImage本身是异步实现的(比如用URLSession做网络请求),只需要把leave()放到下载的完成回调里就行,示例如下:
先定义异步版的downloadImage
func downloadImage(_ urlString: String, completion: @escaping () -> Void) { guard let url = URL(string: urlString) else { completion() return } URLSession.shared.dataTask(with: url) { data, response, error in // 这里处理下载后的逻辑:比如保存图片、处理错误等 if let data = data { // 示例:保存图片到临时目录 try? data.write(to: URL(fileURLWithPath: "/tmp/\(url.lastPathComponent)")) } // 下载完成后调用completion completion() }.resume() }
对应的并行执行代码
let urls:[String] = [ "http://acme.com/one.jpeg", "http://acme.com/two.jpeg", "http://acme.com/three.jpeg", ] let downloadGroup = DispatchGroup() for url in urls { downloadGroup.enter() // 直接调用异步方法即可,URLSession本身会在后台队列执行 downloadImage(url) { downloadGroup.leave() } } downloadGroup.notify(queue: DispatchQueue.main) { print("all images downloaded.") }
这样就能完美实现所有图片的并行下载,并且确保所有任务完成后才打印提示信息。
内容的提问来源于stack exchange,提问作者Pono
相关产品推荐
相关产品推荐

