Je m'abonne 2 fois pour 1 UIButton:
Code:
class ProductionSize {
var id : Int?
var size: Int = 0
var name: String = ""
}
class ProductionCell: UICollectionViewCell {
var rxBag = DisposeBag()
// this will be set in the (cellForItemAt indexPath: IndexPath) of collection view
var productionSize: ProductionSize? {
didSet {
showProductionSize()
prepareButton()
}
}
func showProductionSize() {
// ... code for showing ProductionSize in labels
}
func prepareButton() {
// This for subscribing for every click for displaying purpose
btn_increase.rx.tap
.subscribe(){event in
self.increaseClicked()
}
.addDisposableTo(rxBag)
// this for subscribing for sending webservice request after 1 second of clicking the button (so that if user click it quickly i send only last request)
btn_increase.rx.tap
.debounce(1.0, scheduler: MainScheduler.instance)
.subscribe(){ event in self.updateOnWS() }
.addDisposableTo(rxBag)
}
func increaseClicked() {
productionSize.size = productionSize.size + 1
showProductionSize()
}
func updateOnWS() {
// code for updating on webservice with Moya, RxSwift and Alamofire§
}
// when scrolling it gets called to dispose subscribtions
override func prepareForReuse() {
rxBag = DisposeBag()
}
}
Le problème:
Étant donné que la suppression se produit sur prepareForReuse()
, si je clique plusieurs fois sur le bouton et que je défile immédiatement, les appels du service Web sont supprimés et ne sont pas mis à jour.
ce que j'ai essayé:
Ajout de addDisposableTo(vc?.rx_disposableBag)
au ViewController DisposableBag parent.
Le problème , les abonnements accumulés et à chaque clic la updateWS()
appelée plusieurs fois qui est inscrite sur chaque parchemin et jamais éliminée.
J'ai essayé de supprimer la réinitialisation de disposableBag de prepareForReuse()
.
Le problème , Encore une fois, les abonnements aux boutons sont dupliqués et accumulés et de nombreux appels de service Web sont appelés à chaque clic.
Question: Comment puis-je obtenir les abonnements debounce
appelés à la fin et jamais répétés avec plusieurs abonnements (dans le cas de addDisposableTo
viewController Bag)?
Puisque prepareButton()
est toujours appelé dans le (cellForItemAt indexPath: IndexPath) de la vue de collection, vous pouvez essayer ceci:
func prepareButton() {
self.rxBag = nil
let rxBag = DisposeBag()
// This for subscribing for every click for displaying purpose
btn_increase.rx.tap
.subscribe(onNext: { [weak self] _ in
self?.increaseClicked()
})
.addDisposableTo(rxBag)
// this for subscribing for sending webservice request after 1 second of clicking the button (so that if user click it quickly i send only last request)
btn_increase.rx.tap
.debounce(1.0, scheduler: MainScheduler.instance)
.subscribe(onNext: { [weak self] _ in
self?.updateOnWS()
})
.addDisposableTo(rxBag)
self.rxBag = rxBag
}
Supprimez l'implémentation prepareForReuse()
.
addDisposableTo(vc?.rx_disposableBag)
ajouté au ViewController DisposableBag parent.Le problème, les abonnements accumulés et à chaque clic le updateWS () appelé plusieurs fois qui est abonné à chaque défilement et jamais supprimé.
Il est possible que votre self.updateOnWS()
soit appelé plusieurs fois en raison de la façon dont vous vous abonnez au toucher du bouton.
btn_increase.rx.tap
.debounce(1.0, scheduler: MainScheduler.instance)
.subscribe(){ event in self.updateOnWS() }
.addDisposableTo(rxBag)
Comme vous pouvez le voir, vous vous abonnez à tous les événements à l'aide de la méthode subscribe()
. Cela signifie que tous les événements Rx (onNext
, onError
, onCompleted
, onSubscribed
et onDisposed
) déclenchent le self.updateOnWS()
. Vous pouvez vérifier si c'est le cas en imprimant l'objet event
pour voir quel événement a été déclenché.
onNext
uniquementUn correctif possible pourrait être de ne souscrire qu'à l'opération onNext
.
btn_increase.rx.tap
.debounce(1.0, scheduler: MainScheduler.instance)
.subscribe(onNext: { [weak self] (_ : Void) in
self?.updateOnWS()
})
.addDisposableTo(vc?.rxdisposableBag)
En utilisant le DisposeBag
du contrôleur de vue, vous pouvez vous assurer que l'opération continue toujours même si la cellule est supprimée (lorsque vous faites défiler vers le bas). Toutefois, si vous en avez besoin pour supprimer l'abonnement lorsque la cellule est supprimée, utilisez le DisposeBag
de la cellule, pas le contrôleur de vue.
Notez que la référence à self
est spécifiée comme étant faible, afin que vous puissiez éviter les fuites de mémoire. En spécifiant qu'il est faible, il vous fournira une référence à soi qui est facultative.
Sans cela, la fermeture que vous avez créée pour le bloc onNext
conservera une référence forte au self
qui est votre UICollectionViewCell
, qui à son tour est propriétaire de la fermeture dont nous discutons .
Cela entraînera éventuellement un crash de mémoire insuffisante. Consultez la référence que j'ai publiée dans les commentaires de votre question pour plus d'informations sur les fuites de mémoire causées par un mauvais référencement de soi.