在 RxSwift 中重新启动可观察间隔的正确方法

Correct way to restart observable interval in RxSwift

在我的 OS X 状态栏应用程序中,我使用 interval 函数定期调用外部 api 并显示结果:

Observable<Int>
    .interval(120.0, scheduler: MainScheduler.instance)
    .startWith(-1) // to start immediately
    .flatMapLatest(makeRequest) // makeRequest is (dummy: Int) -> Observable<SummaryResponse?>
    .subscribeNext(setSummary)
    .addDisposableTo(disposeBag)

但是,如果用户在此期间更改了首选项,我想 "restart" 这个间隔并立即进行新调用以反映更改(无需等待下一次调用)。

最好的方法是什么?

  1. 将 observable 存储为 属性 并将其设置为 nil 或对其调用 .dispose()(或两者)并创建一个新的 observable ?
  2. disposeBag 设置为 nil 并创建一个新的可观察对象 ?
  3. 还有其他方法吗?

您要找的是merge。您有两个 Observable,其中一个是 interval,另一个代表偏好更改。你想 merge 将它们合二为一 Observable 与来自两者的元素,当它们出现时立即。

看起来像这样:

// this should really come from somewhere else in your app
let preferencesChanged = PublishSubject<Void>()

// the `map` is so that the element type goes from `Int` to `Void`
// since the `merge` requires that the element types match
let timer = Observable<Int>.timer(0, period: 3, scheduler: MainScheduler.instance).map { _ in () }

Observable.of(timer, preferencesChanged)
    .merge()
    .flatMapLatest(makeRequest)
    .subscribeNext(setSummary)
    .addDisposableTo(disposeBag)

另请注意我是如何使用 timer 而不是 interval,因为它允许我们指定首次触发的时间以及后续触发的时间段。这样,您就不需要 startWith。但是,这两种方法都有效。这是一个偏好问题。

还有一点要注意。这超出了您的问题范围(也许您为了问题而保持简单)但是您应该考虑将结果保留为 Observable 而不是 subscribeNext(setSummary),而不是 bindTodrive UI 或 DB(或任何 "summary")。