Faites attention aux NSTimer
Salut à tous !
Bon je suppose que la plupart d'entre vous le savez déjà , mais faites gaffes aux Timers
J'utilise un timer dans une sous classe de NSObject qui doit être relâchée à un moment ou à un autre pour pouvoir économiser un peu la mémoire.
Je m'étonnais de ne pas voir mon petit log "I have been released".
Donc j'ai jeté un oeil à la docu des Timers (après avoir cherché 5 bonnes minutes d'où ça provenait) :
En gros (pour ceux qui n'aiment pas l'anglais ), le target de votre timer (donc généralement votre classe : self) ne pourra pas être "détruit" tant que le timer sera en marche.
Voilà pour la petite info. Je sais pas si ça a déjà été évoqué mais bon, c'est toujours bon à savoir.
Bon je suppose que la plupart d'entre vous le savez déjà , mais faites gaffes aux Timers
J'utilise un timer dans une sous classe de NSObject qui doit être relâchée à un moment ou à un autre pour pouvoir économiser un peu la mémoire.
Je m'étonnais de ne pas voir mon petit log "I have been released".
Donc j'ai jeté un oeil à la docu des Timers (après avoir cherché 5 bonnes minutes d'où ça provenait) :
It is important to realize that, in keeping with standard Cocoa memory management rules, a timer maintains a strong reference to its target. (That is, in a reference-counted environment a timer retains it target, and in a garbage-collected environment it has a strong reference to the target.) This means that as long as a timer remains valid (and you otherwise properly abide by memory management rules), its target will not be deallocated. As a corollary, this means that it does not make sense for a timer's target to try to invalidate the timer in its dealloc or finalize method"neither method will be invoked as long as the timer is valid.
En gros (pour ceux qui n'aiment pas l'anglais ), le target de votre timer (donc généralement votre classe : self) ne pourra pas être "détruit" tant que le timer sera en marche.
Voilà pour la petite info. Je sais pas si ça a déjà été évoqué mais bon, c'est toujours bon à savoir.
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
http://forum.macbidouille.com/index.php?showtopic=159017&hl=NSTimer
Bon heu donc si je comprend bien le problème, si j'ai une classe Toto qui a une variable d'instance [tt]NSTimer* timer;[/tt], et que typiquement j'ai de sorte d'avoir mon timer qui tourne constamment tant que mon instance de Toto existe... ben en fait ça bloque la destruction de mon instance de Toto ?
Car son retainCount ne descendra jamais à zéro (et donc le dealloc ne sera jamais appelé)... à moins que j'invalide le timer à un moment dans une méthode, ce qui fait que le timer va faire un release sur son target... son retainCount passe à zéro, il appelle dealloc... et fait un [tt][timer invalidate][/tt] qui du coup à cet endroit ne sert plus à rien ??
C'est bizarre pourtant c'est un cas de figure assez classique je trouve, non ? Et j'ai toujours vu procéder comme ça, création du timer dans le init et invalidation dans le dealloc... du coup c'est quoi la préconisation dans ce genre de cas ?? ???
Obligé d'appeler un "destroyTimer:" à ma classe avant de la relâcher.
En gros ça donne ça :
J'avais bêtement cherché s'il n'existe pas une méthode NSTimer du genre "removeFromTarget:"... un peu comme pour le notification center.. mais rien, quedal. Et quand bien même ça aurait existé, ça n'aurait pas marché puisque de toute façon le dealloc n'est pas appelé..
Et j'utilisais un NSTimer au lieu de "performSelectorOnMainThread" beaucoup plus adéquat... Mais c'était il y a presque 3 ans, il y a prescription :P
Je ne connaissais pas cette subtilité. C'est bon à savoir merci.
Tu touches du doigt la bête noir des concepteurs de Garbage Collector (et des utilisateurs...)
Un objet A référence un objet B qui lui même référence l'objet A (c'est le cycle le plus court, mais il peut y en avoir de bien plus grands !).
Vu que la gestion de mémoire en Objective-C est une sorte de Garbage Collector manuel (l'utilisateur décide des compteurs de références), on tombe sur le même os...
La seule préconisation contre ça, c'est ne ne jamais utiliser "this" comme target (et faire attention à ce que la target n'ait aucune référence sur l'objet d'origine sinon on a un cycle encore plus grand et encore plus de problèmes !)
Toutes les autres solutions sont de la bidouille (s'arranger pour tuer le timer au moment de la fermeture de la fenêtre, surcharger "release" pour tuer le timer quand le retainCount est à 1...)