L'essentiel : Quelles sont les raisons officielles de ne pas utiliser retainCount ?
La gestion de l'autorelease est la plus évidente : vous n'avez aucun moyen de savoir avec certitude combien de références représentées par l'objet retainCount
sont dans un pool d'autorelease local ou externe (sur un thread secondaire, ou dans le pool local d'un autre thread).
De plus, certaines personnes ont des difficultés avec les fuites, et à un niveau plus élevé, le comptage des références et le fonctionnement des pools d'autorelease à des niveaux fondamentaux. Ils écriront un programme sans se soucier (ou presque) du comptage de référence correct, ou sans apprendre à compter correctement. Cela rend leur programme très difficile à déboguer, à tester et à améliorer - c'est aussi une rectification qui prend beaucoup de temps.
La raison pour laquelle nous décourageons son utilisation (au niveau du client) est double :
1) La valeur peut varier pour de nombreuses raisons. Le filage à lui seul est une raison suffisante pour ne jamais lui faire confiance.
2) Vous devez encore mettre en œuvre un comptage correct des références. retainCount
ne vous sauvera jamais d'un comptage de référence déséquilibré.
Y a-t-il jamais une seule situation où cela pourrait être utile ?
Vous pourrait En fait, vous ne pourriez pas l'utiliser de manière significative si vous écriviez vos propres allocateurs ou votre propre système de comptage de références, ou si votre objet vivait sur un seul thread et que vous aviez accès à n'importe quel système de comptage de références. et tous les pools d'autorelease dans lesquels il pourrait exister. Cela implique également que vous ne le partagerez pas avec des API externes. La façon la plus simple de simuler ceci est de créer un programme avec un thread, zéro autorelease pool, et de faire votre comptage de référence de la façon "normale". Il est peu probable que vous ayez un jour besoin de résoudre ce problème ou d'écrire ce programme pour des raisons autres que "académiques".
Comme aide au débogage : vous pourrait utilisez-le pour vérifier que le nombre de retenues n'est pas anormalement élevé. Si vous adoptez cette approche, soyez attentif aux variations d'implémentation (certaines sont citées dans ce billet), et ne vous y fiez pas. Ne commettez même pas les tests dans votre référentiel SCM.
Il peut s'agir d'un diagnostic utile dans des circonstances extrêmement rares. Il peut être utilisé pour détecter :
-
Sur-entretien : Une allocation avec un déséquilibre positif dans le nombre de retenues n'apparaît pas comme une fuite si l'allocation est accessible par votre programme.
-
Un objet qui est référencé par de nombreux autres objets : Une illustration de ce problème est une ressource ou une collection partagée (mutable) qui fonctionne dans un contexte multithread - l'accès ou les changements fréquents à cette ressource/collection peuvent introduire un goulot d'étranglement significatif dans l'exécution de votre programme.
-
Niveaux de libération automatique : La location automatique, les pools de location automatique et les cycles de maintien/libération automatique ont tous un coût. Si vous devez minimiser ou réduire l'utilisation et/ou la croissance de la mémoire, vous pourriez utiliser cette approche pour détecter les cas excessifs.
D'après le commentaire de Bavarious (ci-dessous) : une valeur élevée peut également indiquer une allocation invalidée (instance désallouée). Il s'agit d'un détail d'implémentation, et encore une fois, non utilisable dans le code de production. La messagerie de cette allocation entraînerait une erreur lorsque les zombies sont activés.
Que faut-il faire à la place ?
Si vous n'êtes pas responsable du retour de la mémoire à self
(c'est-à-dire que vous n'avez pas écrit d'allocateur), laissez-le tranquille - il est inutile.
Vous devez apprendre à compter correctement les références.
Pour mieux comprendre l'utilisation de release et autorelease, installez quelques points d'arrêt et comprenez comment ils sont utilisés, dans quels cas, etc. Vous devrez toujours apprendre à utiliser correctement le comptage de références, mais cela peut vous aider à comprendre pourquoi il est inutile.
Encore plus simple : utiliser Instruments pour suivre les allocations et les comptages de réf, puis analyser les comptages de réf et les callstacks de plusieurs objets dans un programme actif.
Historique/explicatif : Pourquoi Apple fournit-elle cette méthode dans le protocole NSObject si elle n'est pas destinée à être utilisée ? Le code d'Apple s'appuie-t-il sur retainCount dans un but précis ? Si oui, pourquoi n'est-il pas caché quelque part ?
Nous pouvons supposer qu'il est public pour deux raisons principales :
1) Comptage des références correctes dans les environnements gérés. C'est bien pour les allocateurs d'utiliser retainCount
-- vraiment. C'est un concept très simple. Quand -[NSObject release]
est appelé, le compteur ref (sauf s'il est surchargé) peut être appelé, et l'objet peut être désalloué si retainCount
est 0 (après avoir appelé dealloc). Tout ceci est très bien au niveau de l'allocateur. Les allocateurs et les zones sont (largement) abstraits donc... cela rend le résultat sans signification pour les clients ordinaires. Voir le commentaire avec bbum (ci-dessous) pour plus de détails sur le pourquoi de cette situation. retainCount
ne peut pas être égal à 0 au niveau du client, de la désallocation des objets, des séquences de désallocation, etc.
2) Pour la rendre disponible aux sous-classeurs qui veulent un comportement personnalisé, et parce que les autres méthodes de comptage de références sont publiques. Cela peut être pratique dans certains cas, mais c'est typiquement utilisé pour de mauvaises raisons (par exemple, les singletons immortels). Si vous avez besoin de votre propre schéma de comptage de références, alors cette famille peut valoir la peine d'être surchargée.
Pour une meilleure compréhension : Quelles sont les raisons pour lesquelles un objet peut avoir un nombre de retenue différent de celui qui serait supposé par le code utilisateur ? Pouvez-vous donner des exemples*** de procédures standard que le code du framework pourrait utiliser et qui provoqueraient une telle différence ? Existe-t-il des cas connus où le nombre d'objets conservés est toujours différent de ce qu'un nouvel utilisateur pourrait attendre ?
Encore une fois, une référence personnalisée comptant les schémas et les objets immortels. NSCFString
appartiennent à cette dernière catégorie :
NSLog(@"%qu", [@"MyString" retainCount]);
// Logs: 1152921504606846975
Autre chose qui mérite d'être mentionné à propos de retainCount ?
C'est inutile comme aide au débogage. Apprenez à utiliser les analyses de fuites et de zombies, et utilisez-les souvent -- même après vous maîtrisez le comptage des références.
Mise à jour : bbum a récemment publié un article intitulé retainCount est inutile . L'article contient une discussion approfondie sur les raisons pour lesquelles -retainCount
n'est pas utile dans la grande majorité des cas.