problème d'avoir des rx.appuyez sur pour UIButton dans UICollectionViewCell - RxSwift 3
Je m'abonne 2 fois pour 1 UIButton :
- D'un premier abonnement, pour la mise à jour de l'INTERFACE utilisateur sur chaque clic
- Deuxième abonnement, pour mettre à jour les valeurs de Service Web toutes les 1 seconde après avoir accumulé clics.
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:
Depuis le jeter arrive sur prepareForReuse()
, Si je clique sur le bouton plusieurs fois et faites défiler immédiatement, le webservice appels obtient éliminés et non mis à jour.
ce que j'ai essayé:
-
Ajouté
addDisposableTo(vc?.rx_disposableBag)
pour le parent ViewController DisposableBag.Le problème, le cumul des abonnements et sur chaque clic de la
updateWS()
appelé de nombreuses fois ce qui est inscrit sur chaque rouleau et jamais disposé. -
J'ai essayé de supprimer le disposableBag ré-initialisation de
prepareForReuse()
.Le problème, de Nouveau, les abonnements pour les boutons se doubler et du cumul et de nombreux webservice appels d'obtenir appelée à chaque clic.
Question:
Comment puis-je obtenir le debounce
abonnements appelé à la fin et de ne jamais répété avec plusieurs abonnements (en cas de addDisposableTo
viewController Sac) ?
- Pas sûr au sujet de votre cas, afin de préciser: c'Est le
productionSize
utilisé dans votreupdateOnWS
? Tel que l'utilisateur peut appuyer sur le bouton plusieurs fois, et puis quand ils cesser de taraudage, le nombre (c'est à dire tapé 5 fois) 5 est utilisé pour le réseau d'appel? Et quel doit être le comportement de l'être lorsque vous faites défiler vers le bas et d'en disposer de la cellule; le réseau demande d'être éliminés ou faut-il encore l'être? Et faut-il produire la taille de l'INTERFACE utilisateur d'être mis à jour sur le robinet de l'utilisateur, ou sur le succès de la réponse de la demande de réseau? - Aussi, soyez prudent avec la façon dont vous utilisez
self
à l'intérieur de fermetures, ce qui peut provoquer des fuites de mémoire qui s'ajoutent, surtout quand il est dansUITableViewCell
s ouUICollectionViewCell
s. Il empêche l'objet d'être éliminés. Voir stackoverflow.com/questions/40583685/... - - je mettre à jour le productionSize chaque clic alors que sur le webservice appel, je vais prendre le dernier productionSize de la valeur et de l'envoyer dans le updateOnWS. si appuyez 5 fois, il n'est mis à jour 1 fois sur le réseau. je ne pas attendre la réponse, pour une meilleure expérience utilisateur, je montre l'interface utilisateur met à jour-je uodate si la demande a été réalisé avec succès
- Quel doit être le comportement de l'être lorsque vous faites défiler vers le bas et d'en disposer de la cellule; le réseau demande d'être éliminés ou faut-il encore l'être?
- la demande doit être effectuée
Vous devez vous connecter pour publier un commentaire.
Depuis
prepareButton()
est toujours appelé dans l' (cellForItemAt indexPath: IndexPath) de la vue de collection, vous pouvez essayer ce:Supprimer la
prepareForReuse()
mise en œuvre.Il est possible que votre
self.updateOnWS()
est appelée plusieurs fois, en raison de la façon dont vous vous abonnez à le bouton du robinet.Comme vous pouvez le voir, vous vous abonnez à tous les événements à l'aide de la
subscribe()
méthode. Cela signifie que tous les Rx événements (onNext
,onError
,onCompleted
,onSubscribed
, etonDisposed
) déclencher leself.updateOnWS()
. Vous pouvez vérifier si c'est le cas, par l'impression de l'event
objet pour voir ce que l'événement a été déclenché.Abonnez-vous sur
onNext
seulementUne solution possible pourrait être seulement de vous abonner à la
onNext
opération.À l'aide de la
DisposeBag
de la vue-contrôleur, vous pouvez vous assurer que l'opération se poursuit toujours, même si la cellule devient éliminés (lorsque vous faites défiler vers le bas). Cependant, si vous en avez besoin pour disposer de l'abonnement lorsque la cellule reçoit éliminés, utilisez leDisposeBag
de la cellule, et non pas le point de vue du contrôleur.Note de côté - fuite de Mémoire
Avis que la référence à
self
est spécifié à être faible, de sorte que vous pouvez empêcher les fuites de mémoire de passe. En spécifiant qu'il soit faible, elle vous fournira une référence à soi qui est facultatif.Sans cela, la fermeture que vous avez créé pour le
onNext
bloc conservent une référence forte à laself
qui est votreUICollectionViewCell
, qui détient à son tour la très de fermeture, nous sommes en train de discuter.Ce qui peut éventuellement causer un incident de mémoire. Voir la référence que j'ai posté sur les commentaires de votre question pour plus de choses à lire sur les fuites de mémoire due à un mauvais référencement de soi.
.addDisposableTo(vc?.rxdisposableBag)
. l'ancien abonnements ne sont pas disposés à le faire défiler, d'accumuler de nombreux abonnements et de nombreux appels de la mise en œuvre de webservice.dispose
sur l'objet d'abonnement. Ou avoir unDisposeBag
que vous pouvez ré-instancier pour simuler un en disposer.debounce
,throttle
opérateurs, et même sans doute de voir sibuffer
avecfilter
à la conditioncount > 0
obtient le comportement que je veux. Tout ce qui pourrait probablement réduire la souscription du code de s'exécuter plusieurs fois. Pour l'élimination des anciens abonnements, je voudrais utiliser un jeter le sac que j'ai nettoyer manuellement ou considé l' `flatMapLatest
de l'opérateur. Si la réponse a aidé, s'il vous plaît marquer comme acceptée. 🙂