30 votes

Comment supprimer la KVO d'une propriété faible ?

J'ai une vue (nous l'appellerons vue A) qui a une weak à sa vue supérieure (vue B). La vue A envoie un KVO à sa vue supérieure, la vue B. Puisque la référence de la vue A à la vue B est une propriété faible (pour éviter un cycle de retenue), comment puis-je supprimer l'observateur (A observant B) ? La référence de la vue A à la vue B est réduite à néant avant que j'aie la possibilité de la supprimer.

A survit à B puisque le contrôleur de vue a une référence forte à A. Voici le message du journal des fuites :

An instance 0x9ac5200 of class UITableView was deallocated while key value observers were still registered with it. Observation info was leaked, and may even become mistakenly attached to some other object. Set a breakpoint on NSKVODeallocateBreak to stop here in the debugger. Here's the current observation info:
<NSKeyValueObservationInfo 0x8660360> (
<NSKeyValueObservance 0x8660320: Observer: 0x8660020, Key path: contentOffset, Options: <New: YES, Old: NO, Prior: NO> Context: 0x8660020, Property: 0x864ac80>
)

B est un UITableView. En plaçant un point d'arrêt à NSKVODeallocateBreak donne des résultats inutiles.

En A removeFromSuperview J'essaie de supprimer l'observateur mais la référence de A à B est déjà nil .

Passage à unsafe_unretained et faire les choses plus manuellement ou appeler [A removeFromSuperview] dans le contrôleur de vue dealloc résout le problème. J'aimerais savoir comment résoudre ce problème à l'aide d'une weak propriété cependant.

Voici le code correspondant : https://gist.github.com/2822776

2voto

Je trouve tout type de code requis spécialement pour ce cas vraiment inutile puisque la suppression peut être automatisée.

Avec l'introduction de l'ARC, Apple aurait dû prévoir la suppression automatique des observateurs, ce qui aurait permis de résoudre des cas comme celui-ci, mais ce n'est malheureusement pas le cas. Mais j'ai créé ma propre catégorie qui ajoute cette fonctionnalité manquante : https://github.com/krzysztofzablocki/SFObservers J'ai expliqué comment j'y suis parvenu sur mon blog : http://www.merowing.info/2012/03/automatic-removal-of-nsnotificationcenter-or-kvo-observers/

Si vous regardez ma solution, vous remarquerez qu'elle fait en sorte que le code original soit appelé, même si l'une des méthodes en appelle d'autres, de sorte que même si apple change son comportement interne, la catégorie continuera de fonctionner correctement :)

1voto

Stream Points 3624

Vous pourriez définir une propriété faible explicite faisant référence à la vue supérieure, puis observer self avec un chemin de clé comme @"propertyReferringSuperview.propertyOfSuperview" ? Lorsque vous recevez une notification de la KVO, vous vérifiez si self.propertyReferringSuperview == nil et cesser d'observer @"propertyReferringSuperview.propertyOfSuperview" .

0voto

Au lieu d'ajouter une propriété faible, vous pourriez simplement utiliser la fonction superview et mettre en œuvre willMoveToSuperview: pour ajouter/supprimer l'observation KVO.

- (void)willMoveToSuperview:(UIView *)newSuperview {
    [self.superview removeObserver:self forKeyPath:@"contentOffset" context:context];
    [newSuperview addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:context];
    [super willMoveToSuperview:newSuperview]; // optional as default implementation does nothing
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X