Swift:循环中调用带Completion Handler的方法问题
嘿,我来帮你搞定在for asset: PHAsset in photoAssets循环里调用异步上传方法的问题!你现在的postLandGradingImages已经封装了API请求,但直接在循环里调用的话,会一下子发起所有异步请求,很容易出现并发过多、顺序混乱或者难以跟踪完成状态的问题。下面给你两种实用的解决方案,按需选择:
方案1:串行上传(严格按顺序处理)
适合需要保证上传顺序的场景(比如必须传完前一张再传后一张),我们用递归来实现逐个处理:
func uploadAssetsSequentially(_ assets: [PHAsset], currentIndex: Int = 0) { // 所有asset处理完成,退出递归 guard currentIndex < assets.count else { print("✅ 所有图片上传完成!") return } let currentAsset = assets[currentIndex] // 先把PHAsset转换成你的ImagesData格式(这里需要你根据实际结构实现转换逻辑) convertPHAssetToImagesData(currentAsset) { imagesData in guard let validData = imagesData else { print("⚠️ 第\(currentIndex)张图片转换失败,跳过") self.uploadAssetsSequentially(assets, currentIndex: currentIndex + 1) return } // 调用你的上传方法 self.postLandGradingImages(cellHolder: [validData]) { isSuccess in if isSuccess { print("🎉 第\(currentIndex)张图片上传成功") } else { print("❌ 第\(currentIndex)张图片上传失败") } // 处理下一张图片 self.uploadAssetsSequentially(assets, currentIndex: currentIndex + 1) } } } // 辅助方法:将PHAsset转为ImagesData(示例逻辑,你需要根据自己的ImagesData结构调整) func convertPHAssetToImagesData(_ asset: PHAsset, completion: @escaping (ImagesData?) -> Void) { let requestOptions = PHImageRequestOptions() requestOptions.isNetworkAccessAllowed = true requestOptions.deliveryMode = .highQualityFormat PHImageManager.default().requestImageDataAndOrientation(for: asset, options: requestOptions) { imageData, _, _, _ in guard let data = imageData else { completion(nil) return } // 假设你的ImagesData需要图片数据和其他字段,这里按需初始化 let result = ImagesData(imageData: data, /* 其他必要参数 */) completion(result) } }
使用方式很简单:
// 传入你的photoAssets数组即可开始串行上传 uploadAssetsSequentially(photoAssets)
方案2:并行上传(控制并发数)
如果追求上传效率,但又不想发起太多并发请求给服务器造成压力,可以用OperationQueue控制同时上传的数量:
func uploadAssetsInParallel(_ assets: [PHAsset], maxConcurrentCount: Int = 3) { let uploadQueue = OperationQueue() uploadQueue.maxConcurrentOperationCount = maxConcurrentCount // 设置最大并发数,可根据服务器承受能力调整 for (index, asset) in assets.enumerated() { let uploadOp = BlockOperation { // 用信号量等待异步转换和上传完成 let semaphore = DispatchSemaphore(value: 0) self.convertPHAssetToImagesData(asset) { imagesData in guard let validData = imagesData else { print("⚠️ 第\(index)张图片转换失败") semaphore.signal() return } self.postLandGradingImages(cellHolder: [validData]) { isSuccess in isSuccess ? print("🎉 第\(index)张图片上传成功") : print("❌ 第\(index)张图片上传失败") semaphore.signal() } } semaphore.wait() } uploadQueue.addOperation(uploadOp) } // 监听所有上传任务完成 uploadQueue.completionBlock = { DispatchQueue.main.async { print("✅ 所有上传任务已结束!") } } }
使用方式:
// 最多同时上传3张,可按需调整并发数 uploadAssetsInParallel(photoAssets, maxConcurrentCount: 3)
小提示
- 你的
postLandGradingImages里用DispatchQueue.main.async包裹completion是对的,确保后续如果有UI更新操作能在主线程执行 - 如果需要批量上传多组图片,可以先把多个PHAsset转换成ImagesData数组,再分批调用
postLandGradingImages - 建议给上传失败的情况加上重试逻辑,比如失败后重试1-2次,提升成功率
内容的提问来源于stack exchange,提问作者user979331
相关产品推荐
相关产品推荐

