RxSwift L'eliminazione di una sottoscrizione richiama la disposizione di un'altra sottoscrizione
Ho un PublishSubject<InfoData>
in un ViewController. E mi iscrivo ad esso, quindi quando emette un evento, mostro l'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 un ViewController ho un tableView con intestazioni di sezione. La vista dell'intestazione della sezione ha un'estensione infoMessageAction: PublishSubject<InfoData?>
. Quando si avvia una visualizzazione per viewForHeaderInSection
effettuo un abbonamento tra infoMessageAction
e 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
}
Quando la visualizzazione dell'intestazione viene avviata per la prima volta, tutto funziona correttamente, infoMessageAction
attiva il infoData
che a sua volta attiva la presentazione di AlertViewController. Quando scorro la vista dell'intestazione oltre lo schermo l'abbonamento tra view.infoMessageAction
e infoData
dispone (che è un comportamento previsto quando la vista è stata definita).
Ma ho eliminato anche l'abbonamento tra infoData
e ViewController. Ricevo event completed
e dispose
per view.infoMessageAction
<-> infoData
abbonamento e anche event completed
e dispose
per infoData
<-> abbonamento a ViewController.
Mi aspetto che solo view.infoMessageAction
<-> l' infoData
abbonamento debba interrompersi. Inoltre entrambi gli abbonamenti vengono smaltiti da disposeBag differenti. Perché l' infoData
abbonamento a <-> ViewController viene eliminato e come prevenirlo?
Grazie in anticipo!
Risposte
Quando la tua FutureSpendingsHeaderView
è deinizializzata, qualunque vista che è la fonte infoMessageAction
viene anche deinizializzata, e quella vista emette un completed
evento in quel momento. L'evento completato viene trasmesso al infoData
quale emette il proprio evento completato.
Una volta che un Observable ha emesso un evento completato, è fatto. Non può emettere altri eventi. Quindi l'abbonamento ad esso viene smaltito.
La tua risposta @Alex cambia l'equazione cambiando l'ordine in cui le cose all'interno della tua vista vengono deinizializzate. DisposeBag viene ora deinizializzato per primo, interrompendo la catena osservabile prima che la vista invii l'evento completato.
Una soluzione migliore sarebbe usare a PublishRelay
piuttosto che a PublishSubject
. I relè non emettono eventi completati.
Anche meglio di così sarebbe sbarazzarsi completamente del soggetto e fare qualcosa come:
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
}
Trovato il problema, se qualcuno deve affrontare una situazione del genere. Nella vista dell'intestazione della sezione ho iniziato disposeBag
come costante e ho pensato che tutto il resto fosse gestito da RxSwift stesso quando la vista è stata definita. Quindi ho aggiornato la vista a:
var disposeBag = DisposeBag()
deinit {
disposeBag = DisposeBag()
}
Ora l'abbonamento viene smaltito secondo necessità.