Combine框架多异步请求错误处理:适配差异化故障响应需求
解决Combine中Zip操作符的差异化错误处理需求
你的核心需求是让两个请求的错误处理逻辑分离:学生API失败必须终止流程并提示错误,地址API失败则用默认值继续执行。可以通过为地址请求添加错误兜底逻辑,再结合Zip操作符来实现,具体方案如下:
修改思路
- 学生API请求:保留原有错误抛出逻辑,一旦失败,整个流会进入错误状态,在
sink的receiveCompletion中处理并显示错误。 - 地址API请求:使用
catch操作符捕获错误,返回一个包含空地址数组的默认发布者,确保该请求永远不会抛出错误,让Zip能正常接收它的输出(即使是默认值)。
修改后的完整代码
import Foundation import Combine enum NetworkError: Error { case decodingError case requestFailed } struct StudentDTO: Codable { let name: String let age: Int let addressId: Int } struct AddressDTO: Codable { let id: Int let town: String } struct Student { let name: String let age: Int let town: String } func m1<T: Codable>(url: String, type: T.Type) -> Future<T, NetworkError> { return Future { promise in // 这里替换为实际的URLSessionDataTask请求逻辑 } } // 声明一个用于存储订阅的变量,避免订阅被提前释放 var cancellables = Set<AnyCancellable>() // 处理地址API的错误:失败时返回空数组 let addressRequest = m1(url: "", type: [AddressDTO].self) .catch { _ in Just([AddressDTO]()) // 错误时返回空的地址数组 } Publishers.Zip( m1(url: "", type: [StudentDTO].self), addressRequest ) .sink(receiveCompletion: { completion in if case .failure(let error) = completion { // 仅当学生API失败时会进入这里,显示错误信息 print("学生API请求失败:\(error)") } }, receiveValue: { studentList, addresses in // 正常处理逻辑,地址API失败时addresses是空数组 let addressDict = addresses.reduce(into: [Int: String]()) { dict, address in dict[address.id] = address.town } let students = studentList.map { student in Student( name: student.name, age: student.age, town: addressDict[student.addressId] ?? "" ) } // self?.processStudents(students: students) }) .store(in: &cancellables)
关键细节说明
- 地址请求的错误兜底:
catch操作符会捕获地址请求的所有错误,返回Just([AddressDTO]())——这是一个立即发射空数组的发布者,确保地址请求的流永远不会进入失败状态,Zip操作符就能正常等待两个请求完成。 - 学生请求的错误传递:学生请求没有添加错误处理,所以一旦它失败,整个Zip流会触发
receiveCompletion的.failure分支,在这里可以处理错误提示逻辑。 - 数据处理兼容:当地址API失败时,
addresses是空数组,转换后的addressDict也是空字典,学生的town会使用默认值"",符合业务中"继续运行"的需求。
内容的提问来源于stack exchange,提问作者nath
相关产品推荐
相关产品推荐

