Запретить удаление PublishSubject (RxSwift) - PullRequest
0 голосов
/ 29 мая 2018

Я борюсь с конкретным вариантом использования, включающим PublishSubject RxSwift.

Для простоты несущественные детали были опущены.

Существует настройка 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)
}

Проблема в , так как сетевой запрос может быть неудачным и наблюдаемый, который возвращается из *Метод 1015 * выдаст ошибку, вся подписка на buttonDidTapSubject во ViewModel будет ликвидирована.И все другие нажатия на кнопку не будут вызывать последовательность входа в ViewModel.

Есть ли способ избежать такого поведения?

1 Ответ

0 голосов
/ 29 мая 2018

Вы можете использовать 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)
  }
...