如何通过PassthroughSubject从Service层向ViewModel传递错误
Combine Service层错误传递解决方案
问题核心
当前Service层代码仅在请求成功时通过PassthroughSubject传递数据,但忽略了receiveCompletion中的错误处理逻辑,导致ViewModel无法接收错误信息。
修复方案1:保留现有Subject模式
修改Service中get()方法的sink回调,在收到错误时通过subject传递错误事件,同时处理完成事件:
class UserService: UserServiceContract { private var cancelBag = CancelBag() private let subject = PassthroughSubject<User, Error>() private var requestHoldBackTimeInterval: TimeInterval { return 0.5 } func get() -> AnyPublisher<User, Error> { let repo: AnyPublisher<User, Error> = UserWebRepository().get() repo.ensureTimeSpan(requestHoldBackTimeInterval) .sink( receiveCompletion: { [weak self] completion in // 传递完成或错误事件到Subject self?.subject.send(completion: completion) }, receiveValue: { [weak self] user in print(user) self?.subject.send(user) } ) .store(in: cancelBag) return subject.eraseToAnyPublisher() } }
关键改动说明
- 在
receiveCompletion回调中直接调用subject.send(completion: completion),将成功完成或失败错误事件统一传递给订阅的ViewModel。 - 移除冗余的
mapError逻辑(原错误已符合Error类型,无需额外转换)。
修复方案2:简化代码(移除Subject)
Combine的链式调用本身支持事件传递,无需额外引入PassthroughSubject,直接返回处理后的Publisher即可,同时减少不必要的资源管理:
class UserService: UserServiceContract { private var requestHoldBackTimeInterval: TimeInterval { return 0.5 } func get() -> AnyPublisher<User, Error> { UserWebRepository().get() .ensureTimeSpan(requestHoldBackTimeInterval) .handleEvents(receiveValue: { print($0) }) // 替代原sink中的打印逻辑 .eraseToAnyPublisher() } }
优势
- 代码更简洁,贴合Combine声明式编程风格。
- 无需手动管理
cancelBag和PassthroughSubject,降低内存泄漏风险。 - 自动传递所有事件(成功值、错误、完成)到ViewModel,无需额外处理。
ViewModel侧验证
原ViewModel代码需补充error属性定义,确保能正确存储错误信息:
final class ViewModel: ObservableObject { @Published var user: User? @Published var error: Error? // 补充错误属性定义 func sendUserRequest() { @Injected var userService: UserServiceContract userService.get() .sink(receiveCompletion: { [weak self] completion in if case let .failure(error) = completion { self?.error = error } }, receiveValue: { [weak self] user in self?.user = user }) .store(in: cancelBag) } }
内容的提问来源于stack exchange,提问作者Ratnesh Shukla
相关产品推荐
相关产品推荐

