在withThrowingTaskGroup中区分处理下载与磁盘存储错误
实现带错误区分的批量图片下载任务组
完全可行,核心思路是在子任务里区分错误类型:下载失败的错误捕获后返回可选值(表示该任务失败但不影响全局),磁盘存储失败的错误直接抛出(触发任务组取消所有任务并向上传递错误)。
具体实现步骤
- 定义区分下载/磁盘错误的枚举,让
downloadFile能抛出不同类型的错误供后续判断 - 修改任务组的输出类型为
SampleImage?,允许子任务返回nil(代表下载失败) - 在子任务中捕获下载类错误,返回
nil;遇到磁盘类错误直接抛出,触发全局取消 - 最终收集结果时过滤掉
nil值,只保留成功下载的图片
完整代码示例
首先定义错误枚举:
enum ImageProcessingError: Error { case downloadFailed(underlying: Error) case diskWriteFailed(underlying: Error) }
然后修改downloadFile方法,将不同阶段的错误包装成对应的类型:
private func downloadFile(from remoteImage: RemoteImageData) async throws -> SampleImage { // 下载阶段 do { let data = try await URLSession.shared.data(from: remoteImage.url).0 // 磁盘存储阶段 do { let url = try saveDataToDisk(data, filename: remoteImage.filename) return SampleImage(localURL: url, originalData: remoteImage) } catch { throw ImageProcessingError.diskWriteFailed(underlying: error) } } catch { throw ImageProcessingError.downloadFailed(underlying: error) } } // 辅助存储方法示例 private func saveDataToDisk(_ data: Data, filename: String) throws -> URL { let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! let fileURL = documentsDir.appendingPathComponent(filename) try data.write(to: fileURL) return fileURL }
最后修改批量下载的任务组代码:
private func batchDownloadImages(from remoteImages: [RemoteImageData]) async throws -> [SampleImage] { try await withThrowingTaskGroup(of: SampleImage?.self) { group in for image in remoteImages { group.addTask(priority: .userInitiated) { do { return try await self.downloadFile(from: image) } catch let error as ImageProcessingError { switch error { case .downloadFailed: // 下载失败,返回nil,不影响其他任务 return nil case .diskWriteFailed: // 磁盘存储失败,直接抛出错误,触发任务组取消所有任务 throw error } } catch { // 其他未知错误,可根据需求选择抛出或返回nil throw error } } } // 收集结果,过滤掉nil值 return try await group.reduce(into: [SampleImage]()) { result, image in if let image = image { result.append(image) } } } }
关键逻辑说明
- 当某个子任务抛出
diskWriteFailed错误时,withThrowingTaskGroup会立即取消所有未完成的子任务,并且将该错误向上抛出,调用方可以捕获这个错误做后续处理 - 子任务遇到
downloadFailed错误时,返回nil,不会触发任务组的取消逻辑,其他任务会继续执行 - 最终结果只包含下载且存储成功的图片,下载失败的项会被过滤掉
内容的提问来源于stack exchange,提问作者Bwgan
相关产品推荐
相关产品推荐

