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

向用户设备保存多张图片时如何处理错误并终止其余异步任务

多图异步保存出错全局终止方案

你当前的问题核心是所有下载、保存任务完全独立运行,没有全局状态管控和运行中任务的持有逻辑,因此单个任务出错后无法中断其余未完成的异步操作,同时会触发多次重复错误回调。可以按以下逻辑改造:


第一步:新增全局管控属性

在当前类中新增三个属性用于状态和任务管理:

// 存储所有正在运行的下载任务
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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 16:45:04