RxSwift La suppression d'un abonnement appelle la suppression d'un autre abonnement
J'ai un PublishSubject<InfoData>
dans un ViewController. Et je m'y abonne, donc quand il émet un événement - je montre le 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)
}
Dans un ViewController, j'ai un tableView avec des en-têtes de section. La vue d'en-tête de section a un infoMessageAction: PublishSubject<InfoData?>
. Lors du lancement d'une vue pour viewForHeaderInSection
je fais un abonnement entre le infoMessageAction
et 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
}
Lorsque la vue d'en-tête est lancée pour la première fois, tout fonctionne correctement - infoMessageAction
déclenche le infoData
qui à son tour déclenche la présentation d'AlertViewController. Lorsque je fais défiler la vue d'en-tête au-delà de l'écran, l'abonnement entre view.infoMessageAction
et infoData
supprime (ce qui est le comportement attendu car la vue a été définie).
Mais je reçois également l'abonnement entre infoData
et ViewController. Je reçois event completed
et dispose
pour l' abonnement view.infoMessageAction
<-> infoData
et aussi event completed
et dispose
pour l' infoData
abonnement <-> ViewController.
Je m'attends à ce que seul l' abonnement view.infoMessageAction
<-> infoData
soit interrompu. Les deux abonnements sont également supprimés par disposerBag. Pourquoi l' infoData
abonnement <-> ViewController est-il supprimé et comment l'empêcher?
Merci d'avance!
Réponses
Lorsque votre FutureSpendingsHeaderView
est désinitialisé, la vue qui est la source de infoMessageAction
est également en cours de désinitialisation, et cette vue émet un completed
événement à ce moment-là. Cet événement terminé est transmis à infoData
qui émet alors son propre événement terminé.
Une fois qu'un observable a émis un événement terminé, c'est fait. Il ne peut plus émettre d'événements. Donc, l'abonnement à celui-ci est supprimé.
Votre réponse @Alex change l'équation en modifiant l'ordre dans lequel les éléments de votre vue sont désinitialisés. Le disposeBag est désinitialisé en premier maintenant, ce qui rompt la chaîne observable avant que la vue envoie l'événement terminé.
Une meilleure solution serait d'utiliser un PublishRelay
plutôt qu'un PublishSubject
. Les relais n'émettent pas d'événements terminés.
Mieux encore, se débarrasser complètement du sujet et faire quelque chose comme:
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
}
Trouvé le problème, si quelqu'un fait face à une telle situation. Dans la vue d'en-tête de section, j'ai commencé disposeBag
comme constante et j'ai pensé que tout le reste était géré par RxSwift lui-même lorsque la vue était définie. J'ai donc mis à jour la vue pour:
var disposeBag = DisposeBag()
deinit {
disposeBag = DisposeBag()
}
Maintenant, l'abonnement est supprimé selon les besoins.