Quand utiliser -retainCount?

110

Je voudrais savoir dans quelle situation avez-vous utilisé -retainCountjusqu'à présent, et éventuellement les problèmes qui peuvent survenir en l'utilisant.

Merci.

Moszi
la source
5
vous ne devriez jamais utiliser le -retainCount.
holex
3
(Sauf lorsque vous devriez le faire. Il est très parfois utile de comprendre ce qui se passe, à condition que vous compreniez que cela peut parfois être très trompeur. Et, bien sûr, ce n'est pas du tout autorisé si vous utilisez ARC.)
Hot Licks

Réponses:

243

Vous ne devriez jamais utiliser -retainCount, car cela ne vous dit jamais rien d'utile. La mise en œuvre des frameworks Foundation et AppKit / UIKit est opaque; vous ne savez pas ce qui est conservé, pourquoi il est conservé, qui le conserve, quand il a été conservé, etc.

Par exemple:

  • On pourrait penser que [NSNumber numberWithInt:1]cela aurait un retainCountde 1. Ce n'est pas le cas. C'est 2.
  • On pourrait penser que @"Foo"cela aurait un retainCountde 1. Ce n'est pas le cas. C'est 1152921504606846975.
  • On pourrait penser que [NSString stringWithString:@"Foo"]cela aurait un retainCountde 1. Ce n'est pas le cas. Encore une fois, c'est 1152921504606846975.

Fondamentalement, puisque tout peut conserver un objet (et donc le modifier retainCount), et puisque vous n'avez pas la source de la plupart du code qui exécute une application, celui d'un objet retainCountn'a pas de sens.

Si vous essayez de découvrir pourquoi un objet n'est pas désalloué, utilisez l'outil Fuites dans Instruments. Si vous essayez de découvrir pourquoi un objet a été désalloué trop tôt, utilisez l'outil Zombies dans Instruments.

Mais ne l'utilisez pas -retainCount. C'est une méthode vraiment sans valeur.

Éditer

Veuillez tout le monde aller sur http://bugreport.apple.com et demander qu'il -retainCountsoit obsolète. Plus il y a de gens qui le demandent, mieux c'est.

modifier # 2

En tant que mise à jour, a [NSNumber numberWithInt:1]maintenant un retainCountde 9223372036854775807. Si votre code s'attendait à ce qu'il soit 2, votre code est maintenant cassé.

Dave DeLong
la source
4
Merci @ Dave-Delong pour vos exemples.
Moszi
1
retientCount est actuellement utile pour les singletons (maintenant la question est de savoir dans quelle mesure les singletons sont utiles ...) - (NSUInteger)retainCount{return NSUIntegerMax;}.
Joe
8
@Joe vous pouvez créer un singleton sans surcharger retainCount.
Dave DeLong
5
@Joe j'en suis conscient; Google "singleton objectif-c" pour toute la discussion sur les raisons pour lesquelles cet exemple n'est pas très bon.
Dave DeLong
2
Une chose que j'utilise - @ DaveDeLong, vous pourriez trouver cela faux aussi, mais je ne pense pas - est d'écraser les deallocs et les inits et d'y mettre NSLogs (même avec ARC). Cela me donne une bonne idée de savoir si les objets sont désalloués ou non, ce qui est la vraie question à laquelle nous essayons généralement de répondre.
Dan Rosenstark
50

JAMAIS!

Sérieusement. Ne fais pas ça.

Suivez simplement les directives de gestion de la mémoire et ne publiez que ce que vous alloc, newou copy(ou tout ce que vous avez retaininitialement appelé ).

@bbum l'a mieux dit ici sur SO , et encore plus en détail sur son blog .

Abizern
la source
8
Parce que vous penserez que vous comptez la mémoire, mais que vous le ferez mal.
Abizern
@Abizern - et qu'en est-il de la situation singleton dans l'une des autres réponses?
Moszi
3
Pour ajouter à cela, toutes les informations dont vous pourriez bénéficier -retainCountpeuvent être obtenues (avec beaucoup plus de détails) à partir d'Instruments et de ses outils.
Dave DeLong
3
Pour ajouter à ce que Dave a dit; le nombre absolu de rétention d'un objet est un détail d'implémentation. À la fois un détail des éléments internes de l'objet et / ou un détail de tout autre objet par lequel l'objet a pu être passé. Appel retain, retain, retain, autorelease, autorelease, autoreleasepourrait être un résultat tout à fait valable de passer un objet à travers l'API UIKit, par exemple.
bbum
2
@ d11wtq Si retentionCount jamais == 0, la singularité a été atteinte!
bbum
14

Les objets libérés automatiquement sont un cas où la vérification de -retainCount n'est pas informative et peut être trompeuse. Le nombre de retenues ne vous dit rien sur le nombre de fois où -autorelease a été appelé sur un objet et par conséquent combien de fois il sera libéré lorsque le pool de libération automatique en cours se videra.

Jonas
la source
1
Merci - c'est un bon point. C'est la première réponse qui a en fait une raison expliquée pourquoi ne pas utiliser retientCount, en plus du "ne pas" générique.
Moszi
1
@Moszi: Votre question était "Quand utiliser retentionCount?" - si vous ne vouliez pas poser cette question, vous auriez dû demander autre chose.
Chuck
@chuck - en fait, j'étais intéressé par "quand l'utiliser", mais il semble que chaque réponse sera "jamais" ... Mais - je suppose que vous avez raison. Je laisserai la question ouverte pendant quelques jours, et s'il n'y a pas de réponse autre que jamais, alors j'accepterai «jamais» comme réponse.
Moszi
10

Je ne trouve retainCounts très utile lorsque vérifiée à l' aide « instruments ».

À l'aide de l'outil «allocations», assurez-vous que l'option «Enregistrer le nombre de références» est activée et que vous pouvez accéder à n'importe quel objet et voir son historique retentionCount.

En associant allocs et versions, vous pouvez obtenir une bonne image de ce qui se passe et résoudre souvent les cas difficiles où quelque chose n'est pas publié.

Cela ne m'a jamais laissé tomber - y compris la recherche de bogues dans les premières versions bêta d'iOS.

Egil
la source
5

Jetez un œil à la documentation Apple sur NSObject, elle couvre à peu près votre question: NSObject retentionCount

En bref, retentionCount est probablement inutile pour vous à moins que vous n'ayez implémenté votre propre système de comptage de références (et je peux presque garantir que vous ne l'aurez pas).

Selon les propres mots d'Apple, retentionCount est "généralement sans valeur dans le débogage des problèmes de gestion de la mémoire".

lxt
la source
Tout d'abord merci pour votre réponse. Habituellement, la réaction des gens à cette question est "JAMAIS". (Voir les réponses). En fait, "aucune valeur dans le débogage" ne veut pas dire "JAMAIS". Ma question est donc la suivante: pourquoi le fort sentiment de ne pas l'utiliser (par exemple dans l'implémentation singleton - est à nouveau une des réponses)?
Moszi
Je suppose que vous devrez fournir plus d'informations sur l'utilisation que vous en faites. Une utilisation acceptable serait, comme suggéré par Apple, de remplacer retientCount pour implémenter votre propre système de comptage de références. Mais en pratique, vous ne verrez jamais ça (je ne l'ai jamais vu, de toute façon). La forte réaction vient généralement du fait qu'Apple eux-mêmes ont préconisé (dans leurs groupes de messagerie, les documents, les forums de développement, etc.) de laisser retentionCount seul.
lxt
1
@Moszi: Le débogage est la seule situation dans laquelle la plupart des gens pourraient concevoir qu'il ait de la valeur, donc s'il n'y est pas fiable, il n'est jamais utile. À quelles autres utilisations pensez-vous?
Chuck
4

Bien sûr, vous ne devez jamais utiliser la méthode retentionCount dans votre code, car la signification de sa valeur dépend du nombre de versions automatiques appliquées à l'objet et c'est quelque chose que vous ne pouvez pas prévoir. Cependant, il est très utile pour le débogage - en particulier lorsque vous recherchez des fuites de mémoire dans le code qui appelle des méthodes d'objets Appkit en dehors de la boucle d'événements principale - et il ne devrait pas être obsolète.

Dans vos efforts pour faire valoir votre point de vue, vous avez sérieusement surestimé la nature insondable de la valeur. Il est vrai que ce n'est pas toujours un décompte de référence. Certaines valeurs spéciales sont utilisées pour les indicateurs, par exemple pour indiquer qu'un objet ne doit jamais être désalloué. Un nombre comme 1152921504606846975 semble très mystérieux jusqu'à ce que vous l'écriviez en hexadécimal et obteniez 0xfffffffffffffff. Et 9223372036854775807 est 0x7fffffffffffffff en hexadécimal. Et il n'est vraiment pas si surprenant que quelqu'un choisisse d'utiliser des valeurs comme celles-ci comme indicateurs, étant donné qu'il faudrait près de 3000 ans pour obtenir un retentionCount aussi élevé que le plus grand nombre, en supposant que vous incrémentiez le retentionCount 100000000 fois par seconde.

Marc Culler
la source
3

Quels problèmes pouvez-vous rencontrer en l'utilisant? Tout ce qu'il fait est de renvoyer le nombre de rétention de l'objet. Je ne l'ai jamais appelé et je ne vois aucune raison pour laquelle je le ferais. Je l'ai remplacé dans les singletons pour m'assurer qu'ils ne sont pas désalloués.

ughoavgfhw
la source
2
Il n'y a aucune raison de le remplacer dans le cas du singleton. Il n'y a aucun chemin de code dans Foundation / CoreFoundation utilisé retainCountpour la gestion de la mémoire.
bbum
Le communiqué ne l'utilise-t-il pas pour décider s'il doit appeler dealloc?
ughoavgfhw
2
Nan; l'implémentation interne de retention / release / autorelease a des racines profondes dans CoreFoundation et n'est vraiment pas du tout ce à quoi vous pourriez vous attendre. Allez chercher la source CoreFoundation (elle est disponible) et jetez un œil.
bbum
3

Vous ne devriez pas vous inquiéter des fuites de mémoire tant que votre application n'est pas opérationnelle et ne fait pas quelque chose d'utile.

Une fois que c'est le cas, lancez Instruments et utilisez l'application et voyez si des fuites de mémoire se produisent vraiment. Dans la plupart des cas, vous avez créé un objet vous-même (vous le possédez donc) et avez oublié de le libérer après avoir terminé.

N'essayez pas d'optimiser votre code au fur et à mesure que vous l'écrivez, vos suppositions sur ce qui pourrait perdre de la mémoire ou prendre trop de temps sont souvent fausses lorsque vous utilisez réellement l'application normalement.

Essayez d'écrire du code correct, par exemple si vous créez un objet en utilisant alloc et autres, assurez-vous de le libérer correctement.

ExitToShell
la source
0

Vous ne devriez jamais l'utiliser dans votre code, mais cela pourrait certainement aider lors du débogage

iosdevnyc
la source
0

N'utilisez jamais -retainCount dans votre code. Cependant, si vous utilisez, vous ne verrez jamais qu'il renvoie zéro. Pensez pourquoi. :-)

hrchen
la source
0

Les exemples utilisés dans l'article de Dave sont NSNumber et NSStrings ... donc, si vous utilisez d'autres classes, telles que UIViews, je suis sûr que vous obtiendrez la bonne réponse (le nombre de retenues dépend de l'implémentation, et c'est prévisible).

Peng
la source