【问题标题】:RxSwift combineLatest emits all replayed elements from last ObservableRxSwift combineLatest 从最后一个 Observable 发出所有重放的元素
【发布时间】:2020-11-02 02:42:21
【问题描述】:

在对一组冷的 observable 使用 combineLatest 时,我看到了一些意想不到的结果。它从除最后一个 Observable 之外的所有 Observable 中发出最新的,而是将第一个 (n-1) 个 Observable 中的最新与来自第 n 个 Observable 的每个元素相结合。

let observable = ReplaySubject<Int>.createUnbounded()
let observable2 = ReplaySubject<String>.createUnbounded()

observable.onNext(1)
observable.onNext(2)
observable.onNext(3)
observable.onNext(4)

observable2.onNext("bed")
observable2.onNext("book")
observable2.onNext("table")

let latestObserver = Observable.combineLatest(observable, observable2)

_ = latestObserver
    .subscribe(onNext: {
    print($0)
})
.disposed(by: disposeBag)

产生输出: (4、“床”) (4、《书》) (4,“表”)

我原本预计只会看到 (4, "table") 的输出。

如果我像这样更改可观察对象的顺序:

let latestObserver = Observable.combineLatest(observable2, observable)

我得到输出: (“表格1) (“表”,2) (“表3) (“表”,4)

如果我添加一个最终的任意 Observable,那么我只会看到第一个 Observable 中的最新:

let observable = ReplaySubject<Int>.createUnbounded()
let observable2 = ReplaySubject<String>.createUnbounded()
let observable3 = Observable<Int>.just(42)

observable.onNext(1)
observable.onNext(2)
observable.onNext(3)
observable.onNext(4)

observable2.onNext("bed")
observable2.onNext("book")
observable2.onNext("table")

let latestObserver = Observable.combineLatest(observable, observable2, observable3)

_ = latestObserver
    .subscribe(onNext: {
    print($0)
})
.disposed(by: disposeBag)

产生输出:(4, "table", 42)

这真的是预期的行为吗?

【问题讨论】:

  • 基于这个问题,以及您的最后一个问题,我的印象是您无法跟踪哪些可观察对象是同步的,哪些是异步的......
  • @DanielT。确实。无需过多介绍,它源于模型的协议规范作为视图控制器的输入。该协议指定了我以前习惯于查看 BehaviorRelay 或 BehaviourSubject 的 Observables。视图控制器应该只根据最新值更新其显示和控件,并忽略任何中间重放值。只是试图了解协议的各种可能的未来具体实现的后果 - 这可能超出我的控制范围。我以为我理解了一些事情,但发现了一些惊喜。谢谢
  • 啊,我明白了...无论如何,您都应该避免使用主题(包括 ReplaySubject。)也许这将帮助您避免首先发出所有这些“中间重播值”。 Subjects 只能用于将非 Rx 代码转换为 Rx 并处理依赖循环(其中 Observable 的输出会影响其自身的输入。)

标签: rx-swift combinelatest


【解决方案1】:

让我们分解第一个示例中发生的情况...

你可以用Observable.from代替主题,得到同样的结果……代码中的步骤如下,

  1. 创建两个ReplaySubjects 并用事件加载它们。
  2. combineLatest 运算符订阅第一个主题。
  3. 第一个主题立即重播其所有值。
  4. 由于尚未订阅第二个主题,combineLatest 运算符不会发出任何内容,而是静默吸收值,同时始终存储“最新”的值。
  5. combineLatest 运算符然后订阅第二个主题。
  6. 该主题重播所有值。
  7. 由于 combineLatest 运算符现在已从其每个源接收到下一个事件,它会发出从第二个源发出的值,并结合来自第一个源的最新(即最后一个)。

您的回放主题本质上是同步的。它们在订阅后立即将所有值发送给订阅者。

在您的最后一个示例代码中,由于三个 observable 中的最后一个仅发出一个值,并且只有在其他两个发出所有值之后,您才会看到一个包含前两个 observable 的最新输出的输出。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-25
    • 1970-01-01
    • 1970-01-01
    • 2019-05-27
    • 2018-01-18
    • 1970-01-01
    相关资源
    最近更新 更多