RxSwift простой с последним от не стреляющего - PullRequest
0 голосов
/ 17 мая 2019

У меня наблюдаемая

lazy var user = _user.share(replay: 1)
private let _user = PublishRelay<User>()

в UserState.swift синглтоне. Моя user наблюдаемая получает событие, как только приложение загружается, и я получаю пользователя из бэкэнда.

Позже, в одной из моих ViewModels, я пытаюсь

func profileViewModel(
    viewAppeared: Observable<Void>
) -> (
    title: Observable<String>
) {

    let title = viewAppeared.withLatestFrom(UserState.shared.user) { _, user in
        user.username
    }

    return title

}

За исключением того, что это событие никогда не срабатывает (не попадает внутрь замыкания), потому что user уже сработало до того, как было подписано.

Как я могу выполнить это поведение, когда на viewDidLoad событии я получаю самое последнее значение user из моей наблюдаемой?

EDIT:

В моем синглтоне init, если я добавлю случайное user.subscribe()..., то все это работает. Я так растерялся ...

1 Ответ

1 голос
/ 18 мая 2019

Я вижу проблему. PublishRelay - это просто PublishSubject.

Все, что помещено на него до подписки вашей viewModel, будет потеряно. .Share (replay: 1) помог бы, за исключением того, что что-то должно быть подписано на , что , прежде чем пользователь будет помещен на него, чтобы он «перехватил» событие и кэшировал значение для последующего использования. абонентов.

И даже тогда вам, вероятно, понадобится .share (повтор: 1, область действия: .forever).

Вам нужно помнить, что вы можете настроить все наблюдаемые цепочки, которые вы хотите, но никакие операции в этой цепочке не будут выполняться, пока что-то в конечном итоге не подпишется на эту цепочку.

Измените свое пользовательское состояние на BehaviorSubject (Значение: ноль). Это будет захватывать и удерживать текущего пользователя, если и когда пользователь помещен на него, даже если на него ничего не подписано.

Затем выполните на вашей модели вида что-то вроде следующего.

class ProfileViewModel {
lazy var user = UserState.shared.user.compactMap { $0 }
lazy var name = user.map { $0.username }
lazy var age = user.map { "\($0.age) years old" }
   .do(onNext: { print($0) }
// etc
}

class profileViewController {
  ...
  override func viewDidLoad() {
    ...
    profileViewModel.name
      .subscribe(onNext: { [weak self] name in 
        self?.title = name
      }
      .disposed(by: disposeBag)
  }
}

Обратите внимание, что вы хотите этого, если пользователь (и, следовательно, имя пользователя) может динамически меняться в течение периода, когда отображается этот контроллер представления, и вы хотите, чтобы заголовок обновлялся автоматически.

Также обратите внимание, что, как показано, вы НИКОГДА не увидите возраст пользователя, указанный в операторе .do, так как в настоящее время ничто не подписывается и не привязывается к этой наблюдаемой подцепи.

...