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

如何通过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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 08:10:29