RxSwift 处理一个订阅调用处理另一个订阅

RxSwift Disposing one subscription invokes dispose of another subscription

我在 ViewController 中有一个 PublishSubject<InfoData>。我订阅了它,所以当它发出一个事件时 - 我显示 UIAlertViewController.

let infoData = PublishSubject<InfoData>()
private func bindInfoData() {
     infoData.subscribe(onNext: { [weak self] (title, message) in
         self?.presentInfoSheetController(with: title, message: message)
     }).disposed(by: disposeBag)
}

在 ViewController 中,我有一个包含 header 部分的 tableView。 header 部分视图有一个 infoMessageAction: PublishSubject<InfoData?>。启动 viewForHeaderInSection 的视图时,我在 infoMessageActioninfoData 之间进行订阅。

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
      let view = FutureSpendingsHeaderView(frame: frame)
      view.infoMessageAction
            .compactMap { [=11=] }
            .bind(to: infoData)
            .disposed(by: view.disposeBag)
      return view
}

当 header 视图首次启动时一切正常 - infoMessageAction 触发 infoData 进而触发 AlertViewController 的显示。 当我将 header 视图滚动到屏幕之外时,view.infoMessageActioninfoData 之间的订阅将被处理(这是视图被取消时的预期行为)。

但我也处理了 infoData 和 ViewController 之间的订阅。我收到 event completeddisposeview.infoMessageAction <-> infoData 订阅以及 event completeddisposeinfoData <-> ViewController 订阅。

我预计只有 view.infoMessageAction <-> infoData 订阅会中断。两个订阅也由不同的 disposeBag 处理。为什么 infoData <-> ViewController 订阅会被处置以及如何防止它?

提前致谢!

找到问题了,如果有人遇到这样的情况。 在 header 视图部分,我将 disposeBag 初始化为常量,并认为当视图被取消时,其他一切都由 RxSwift 本身处理。 所以我将视图更新为:

var disposeBag = DisposeBag()
    
deinit {
    disposeBag = DisposeBag()
}

现在订阅会根据需要处理。

当您的 FutureSpendingsHeaderView 被取消初始化时,作为 infoMessageAction 来源的任何视图也将被取消初始化,并且该视图会在那时发出一个 completed 事件。已完成的事件将传递给 infoData,后者会发出自己的已完成事件。

一旦一个 Observable 发射了一个完成的事件,它就完成了。它不能再发出任何事件。所以对它的订阅被处理掉了。

你的回答@Alex 通过改变视图中的事物被取消初始化的顺序来改变等式。 disposeBag 现在首先取消初始化,这会在视图发送完成的事件之前中断可观察链。

更好的解决方案是使用 PublishRelay 而不是 PublishSubject。中继不会发出已完成的事件。

甚至比这更好的方法是完全摆脱这个主题并做类似的事情:

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let view = FutureSpendingsHeaderView(frame: frame)
    view.infoMessageAction
        .compactMap { [=10=] }
        .subscribe(onNext: { [weak self] (title, message) in
            self?.presentInfoSheetController(with: title, message: message)
        })
        .disposed(by: view.disposeBag)
    return view
}