向用户设备保存多张图片时如何处理错误并终止其余异步任务
多图异步保存出错全局终止方案
你当前的问题核心是所有下载、保存任务完全独立运行,没有全局状态管控和运行中任务的持有逻辑,因此单个任务出错后无法中断其余未完成的异步操作,同时会触发多次重复错误回调。可以按以下逻辑改造:
第一步:新增全局管控属性
在当前类中新增三个属性用于状态和任务管理:
// 存储所有正在运行的下载任务 private var ongoingDownloadTasks: [URLSessionDataTask] = [] // 标记保存流程是否已异常终止 private var isSaveAborted = false // 串行队列用于保证全局属性读写的线程安全 private let processQueue = DispatchQueue(label: "com.yourapp.saveImageProcessQueue")
第二步:改造保存触发方法
启动保存流程前先重置全局状态,避免上一次操作的状态干扰:
func saveSelectedImagesToDevice() { // 先重置状态 processQueue.async { [weak self] in guard let self = self else { return } self.isSaveAborted = false self.ongoingDownloadTasks.removeAll() } // 遍历选中图片启动下载 for imageList in imagesListCells { for image in imageList.images where image.selectionState == .onClicked { downloadImage(from: image.url) } } }
第三步:改造下载与保存逻辑
所有异步分支执行前先判断终止状态,任务创建后存入管控数组,任意环节出错都触发全局终止流程:
func downloadImage(from url: String) { processQueue.async { [weak self] in guard let self = self, !self.isSaveAborted, let url = URL(string: url) else { return } let task = URLSession.shared.dataTask(with: url) { [weak self] data, response, error in guard let self = self else { return } self.processQueue.async { // 流程已终止直接中断 guard !self.isSaveAborted else { return } // 下载出错触发终止 guard let data = data, error == nil, let image = UIImage(data: data) else { self.abortAllSaveProcess(errorMsg: "图片下载失败,请检查网络设置") return } UIImageWriteToSavedPhotosAlbum( image, self, #selector(self.image(_:didFinishSavingWithError:contextInfo:)), nil ) } } // 任务加入管控数组后启动 ongoingDownloadTasks.append(task) task.resume() } } @objc func image(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) { processQueue.async { [weak self] in guard let self = self, !self.isSaveAborted else { return } if let _ = error { self.abortAllSaveProcess(errorMsg: "图片保存失败,请确认已开启相册权限") } } }
第四步:新增全局终止方法
异常触发时批量取消所有未完成的任务,更新全局状态并统一触发回调:
private func abortAllSaveProcess(errorMsg: String) { processQueue.async { [weak self] in guard let self = self, !self.isSaveAborted else { return } // 标记流程终止 self.isSaveAborted = true // 取消所有未完成的下载任务 self.ongoingDownloadTasks.forEach { $0.cancel() } self.ongoingDownloadTasks.removeAll() // 主线程触发回调提示 DispatchQueue.main.async { self.delegate?.savedImage(proccessMsg: errorMsg) } } }
补充优化建议
如果需要更灵活的任务管控,也可以使用OperationQueue来管理所有下载保存任务,设置maxConcurrentOperationCount控制并发数,异常时直接调用cancelAllOperations()即可批量终止所有任务,不需要手动管理task数组。
内容的提问来源于stack exchange,提问作者Tomer
相关产品推荐
相关产品推荐

