I have a PublishSubject<InfoData>
in a ViewController. And I subscribe to it, so when it emits an event - I show the 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)
}
In a ViewController I have a tableView with section headers. Section header view has a infoMessageAction: PublishSubject<InfoData?>
. When initiating a view for viewForHeaderInSection
I make a subscription between the infoMessageAction
and infoData
.
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
}
When the header view initiated for the first time all works good - infoMessageAction
triggers the infoData
which in turn triggers presentation of AlertViewController.
When I scroll header view beyond the screen the subscription between view.infoMessageAction
and infoData
disposes (which is expected behavior as the view was deinited).
But I get disposed the subscription between infoData
and ViewController as well. I receive event completed
and dispose
for view.infoMessageAction
<-> infoData
subscription and also event completed
and dispose
for infoData
<-> ViewController subscription.
I expect that only view.infoMessageAction
<-> infoData
subscription should break. Also both subscriptions disposed by different disposeBag. Why is infoData
<-> ViewController subscription get disposed and how to prevent it?
Thanks in advance!
When your FutureSpendingsHeaderView
is deinitialized, whatever view that is the source of infoMessageAction
is also being deinitialized, and that view emits a completed
event at that time. That completed event is passed on to infoData
which then emits its own completed event.
Once an Observable has emitted a completed event, it is done. It can't emit any more events. So the subscription to it is disposed.
Your answer @Alex changes the equation by changing the order that things inside your view get deinitialized. The disposeBag is getting deinitialized first now, which breaks the observable chain before the view sends the completed event.
A better solution would be to use a PublishRelay
rather than a PublishSubject
. Relays don't emit completed events.
Even better than that would be to get rid of the subject entirely and do something like:
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
}