防止处理PublishSubject(RxSwift)

时间:2018-05-29 12:22:36

标签: ios swift cocoa-touch rx-swift

我正在努力使用包含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中登录的序列。

有没有办法避免这种行为?

2 个答案:

答案 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)