我正在努力使用包含RxSwift的PublishSubject的特定用例。
为简单起见,省略了不重要的细节。
有一个MVVM设置。在VC中,我有一个UIButton,网络调用应该分配给它。在ViewModel中,我有一个buttonDidTapSubject: PublishSubject<Void>
。
class ViewModel {
let disposeBag = DisposeBag()
let buttonDidTapSubject = PublishSubject<Void>()
let service: Service
typealias Credentials = (String, String)
var credentials: Observable<Credentials> {
return Observable.just(("testEmail", "testPassword"))
}
init(_ service: Service) {
self.service = service
buttonDidTapSubject
.withLatestFrom(credentials)
.flatMap(service.login) // login method has signature func login(_ creds: Credentials) -> Observable<User>
.subscribe(onNext: { user in print("Logged in \(user)") },
onError: { error in print("Received error") })
.disposed(by: disposeBag)
}
}
class ViewController: UIViewController {
let viewModel: ViewModel
let button = UIButton()
init(_ viewModel: ViewModel) {
self.viewModel = viewModel
}
}
在控制器viewDidLoad
中我制作了一个绑定:
override func viewDidLoad() {
button.rx.tap.asObservable()
.subscribe(viewModel.buttonDidTapSubject)
.disposed(by: disposeBag)
}
问题是,因为网络请求可能失败并且从login(_:)
方法返回的Observable将产生错误,ViewModel中对buttonDidTapSubject
的整个订阅将被处置。按钮上的所有其他按钮都不会触发在ViewModel中登录的序列。
有没有办法避免这种行为?
答案 0 :(得分:0)
您可以使用retry
来阻止完成订阅。如果您只想在特定情况或错误中重试,也可以使用retryWhen
运算符
在视图模型中:
lazy var retrySubject: Observable<Void> = {
return viewModel.buttonDidTapSubject
.retryWhen { error in
if (error == .networkError){ //check here your error
return .just(Void())
} else {
return .never() // Do not retry
}
}
}()
在视图控制器中,我会以另一种方式完成它:
override func viewDidLoad() {
super.viewDidLoad()
button.rx.tap.asObservable()
.flatMap { [weak self] _ in
return self?.viewModel.retrySubject
}
.subscribe(onNext: {
//do whatever
})
.disposed(by: disposeBag)
}
答案 1 :(得分:0)
不确定是否仍然有用-使用PublishRelay(尽管它是RxCocoa)