Swift Combine中如何依次转换Publisher并单独处理各步骤错误?
解决Swift Combine序列执行的类型匹配与错误处理问题
针对你的需求,我们可以通过调整Publisher的类型匹配和错误处理逻辑来实现预期的序列流程,以下是具体方案:
核心思路梳理
- Login错误处理:登录失败时处理错误,直接终止后续流程;登录成功则继续执行
updateImage - UpdateImage错误跳过:无论
updateImage成功或失败(即使后续修改为可能抛出错误的类型),都继续执行getProfile - 最终结果处理:在
sink中统一处理getProfile的结果与错误
完整实现代码
import Combine // 假设的类型定义 struct Token: Equatable { let value: String } struct Status: Equatable { let success: Bool } struct Profile: Equatable { let name: String } enum CustomError: Error { case loginFailed, profileFetchFailed } // 模拟原函数 func login() -> Future<Token, Error> { Future { promise in // 模拟登录逻辑,这里可替换为实际请求 DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { promise(.success(Token(value: "mock_token"))) // 可测试失败场景:promise(.failure(CustomError.loginFailed)) } } } func updateImage() -> Future<Status, Never> { Future { promise in DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { promise(.success(Status(success: true))) } } } func getProfile() -> Future<Profile, Error> { Future { promise in DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { promise(.success(Profile(name: "Mock User"))) // 可测试失败场景:promise(.failure(CustomError.profileFetchFailed)) } } } // 执行序列 var cancellables = Set<AnyCancellable>() login() .catch { loginError in // 处理登录错误:日志、弹窗等操作 print("登录失败:\(loginError)") // 返回Empty Publisher终止后续流程,类型需与上游匹配(Output: Token, Error: Error) return Empty<Token, Error>(completeImmediately: true) } .flatMap { token in // 处理登录成功的token:如保存到本地 print("登录成功,Token:\(token.value)") // 先执行updateImage,无论结果如何都继续调用getProfile return updateImage() // 针对updateImage可能的错误(即使当前是Never,预留后续扩展) .catch { _ in // 跳过错误,返回Empty终止当前分支,继续执行then后的逻辑 return Empty<Status, Never>(completeImmediately: true) } // 忽略updateImage的输出,执行getProfile .then(getProfile()) } .sink(receiveCompletion: { completion in switch completion { case .finished: print("流程执行完成") case .failure(let profileError): print("获取用户信息失败:\(profileError)") } }, receiveValue: { profile in print("获取到用户信息:\(profile.name)") }) .store(in: &cancellables)
关键细节说明
Empty Publisher的作用
- 在登录错误的
catch块中,返回Empty<Token, Error>会立即发送.finished事件,终止整个后续流程,不会将错误传递到sink - 在
updateImage的catch块中(预留扩展用),返回Empty<Status, Never>会跳过错误,让.then操作符继续执行getProfile
- 在登录错误的
类型匹配解决
- 所有
catch块返回的Publisher必须与上游的Output和Error类型严格匹配,否则会出现编译错误 - 使用
.then操作符可以忽略前序Publisher的输出,直接执行下一个Publisher,完美适配“跳过updateImage结果,执行getProfile”的需求
- 所有
流程控制逻辑
- 登录失败:处理错误后终止流程,
sink会收到.finished事件 - 登录成功:先执行
updateImage,无论成功与否,都会执行getProfile,最终sink处理getProfile的结果或错误
- 登录失败:处理错误后终止流程,
内容的提问来源于stack exchange,提问作者Gargo
相关产品推荐
相关产品推荐

