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

问题描述

我在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中,我有一个带有部分标题的tableView。节标题视图具有infoMessageAction: PublishSubject<InfoData?>。为viewForHeaderInSection启动视图时,我在infoMessageActioninfoData之间进行了预订。

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

当头视图首次启动时,一切正常-infoMessageAction触发infoData,这反过来又触发AlertViewController的显示。 当我将标题视图滚动到屏幕之外时,view.infoMessageActioninfoData间的订阅将被处理(这是在取消初始化视图时的预期行为)。

但是我也处理了infoData和ViewController之间的订阅。我收到event completed dispose订阅view.infoMessageActioninfoData,还有event completeddisposeinfoData ViewController订阅

我希望只有view.infoMessageAction infoData订阅会中断。同样,两个订阅都由不同的disposeBag处理。为什么infoData ViewController订阅会被处置以及如何阻止它?

谢谢!

解决方法

发现问题,如果有人遇到这种情况。 在节标题视图中,我将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 { $0 }
        .subscribe(onNext: { [weak self] (title,message) in
            self?.presentInfoSheetController(with: title,message: message)
        })
        .disposed(by: view.disposeBag)
    return view
}