Swift中如何在for循环中正确使用async/await实现图片上传
Swift中for循环结合async/await的正确实现
问题根源
你的代码存在两个核心问题:
uploadImages函数标记了async但内部仍使用传统completion回调,没有利用Swift的async/await机制让函数挂起等待异步操作完成;uploadImage里的for循环只是触发了上传任务,没有等待所有上传完成就直接返回空的data数组。
修复步骤
1. 重构uploadImages为纯async/await版本
把Firebase的回调式API转换为async/await风格,推荐使用SDK自带的异步方法,若版本不支持则手动封装:
方案A:使用Firebase SDK自带的Async方法(推荐)
static func uploadImages(image: UIImage, type: UploadType) async throws -> String { guard let imageData = image.jpegData(compressionQuality: 0.5) else { throw NSError(domain: "UploadError", code: -1, userInfo: [NSLocalizedDescriptionKey: "无法将图片转为JPEG数据"]) } let ref = type.filePath // 等待图片上传完成 _ = try await ref.putDataAsync(imageData, metadata: nil) print("Successfully uploaded image") // 等待获取下载URL let url = try await ref.downloadURL() guard let imageUrl = url.absoluteString else { throw NSError(domain: "UploadError", code: -2, userInfo: [NSLocalizedDescriptionKey: "无法获取图片下载URL"]) } return imageUrl }
方案B:手动用withCheckedThrowingContinuation封装
static func uploadImages(image: UIImage, type: UploadType) async throws -> String { guard let imageData = image.jpegData(compressionQuality: 0.5) else { throw NSError(domain: "UploadError", code: -1, userInfo: [NSLocalizedDescriptionKey: "无法将图片转为JPEG数据"]) } let ref = type.filePath // 封装putData的回调为async/await try await withCheckedThrowingContinuation { continuation in ref.putData(imageData, metadata: nil) { _, error in if let error = error { continuation.resume(throwing: error) } else { continuation.resume() } } } print("Successfully uploaded image") // 封装downloadURL的回调为async/await return try await withCheckedThrowingContinuation { continuation in ref.downloadURL { url, error in if let error = error { continuation.resume(throwing: error) } else if let imageUrl = url?.absoluteString { continuation.resume(returning: imageUrl) } else { continuation.resume(throwing: NSError(domain: "UploadError", code: -2, userInfo: [NSLocalizedDescriptionKey: "无法获取图片下载URL"])) } } } }
2. 修改uploadImage函数,等待所有上传完成
提供两种实现方式,根据业务需求选择:
方式一:顺序上传(逐个等待)
适合对上传顺序有要求的场景:
func uploadImage(images: [UIImage]) async throws -> [String] { var data = [String]() for image in images { let imageUrl = try await ImageUploader.uploadImages(image: image, type: .post) data.append(imageUrl) } return data }
方式二:并发上传(用TaskGroup提高效率)
适合无顺序要求的场景,同时上传多个图片,效率更高:
func uploadImage(images: [UIImage]) async throws -> [String] { return try await withThrowingTaskGroup(of: String.self) { group in for image in images { group.addTask { return try await ImageUploader.uploadImages(image: image, type: .post) } } // 收集所有任务结果 var urls = [String]() for try await url in group { urls.append(url) } return urls } }
调用示例
调用时需用await并处理可能的错误:
do { let imageUrls = try await uploadImage(images: yourImageArray) // 使用获取到的所有图片URL } catch { print("上传失败:\(error.localizedDescription)") }
内容的提问来源于stack exchange,提问作者Taro
相关产品推荐
相关产品推荐

