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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 04:19:02