You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 05:55:06