56 votes

Allocation d'objet et init en Objective C

Quelle est la différence entre les deux façons suivantes d'allouer et d'initier un objet ?

AController *tempAController = [[AController alloc] init];
self.aController = tempAController;
[tempAController release];

et

self.aController= [[AController alloc] init];

La plupart des exemples de la pomme utilisent la première méthode. Pourquoi allouer, initialiser un objet et le libérer immédiatement ?

70voto

benzado Points 36367

Chaque objet a un compte de référence. Lorsqu'il atteint 0, l'objet est désalloué.

En supposant que la propriété a été déclarée comme @property (retain) :

Votre premier exemple, ligne par ligne :

  1. L'objet est créé par alloc il a un nombre de référence de 1.
  2. L'objet est remis à self 's setAController: qui lui envoie un retain (parce que la méthode ne sait pas d'où vient l'objet), incrémentant son compte de référence à 2.
  3. Le code appelant n'a plus besoin de l'objet lui-même, il appelle donc release en décrémentant le nombre de références à 1.

Votre deuxième exemple fait essentiellement les étapes 1 et 2 mais pas la 3, donc à la fin le nombre de références de l'objet est de 2.

La règle est que si vous créez un objet, vous êtes responsable de le libérer lorsque vous en avez fini avec lui. Dans votre exemple, le code a terminé avec tempAController après avoir défini la propriété. C'est la responsabilité de la méthode setter d'appeler retain s'il a besoin que cet objet reste dans le coin.

Il est important de se rappeler que self.property = foo; en Objective-C est en fait un raccourci pour [self setProperty:foo]; et que le setProperty: va conserver ou copier des objets selon les besoins.

Si la propriété a été déclarée @property (copy) Dans ce cas, l'objet aurait été copié au lieu d'être conservé. Dans le premier exemple, l'objet d'origine serait libéré immédiatement ; dans le deuxième exemple, le nombre de références de l'objet d'origine serait de 1 alors qu'il devrait être de 0. Vous devriez donc continuer à écrire votre code de la même manière.

Si la propriété a été déclarée @property (assign) entonces self ne revendique pas la propriété de l'objet, et quelqu'un d'autre doit le conserver. Dans ce cas, le premier exemple serait incorrect. Ces types de propriétés sont rares, généralement utilisées uniquement pour les délégués d'objets.

31voto

mmalc Points 7663

Comme d'autres l'ont noté, les deux extraits de code que vous montrez ne sont pas équivalents (pour des raisons de gestion de la mémoire). Quant à savoir pourquoi le premier est choisi plutôt que le second :

La formulation correcte de cette dernière serait

self.aController= [[[AController alloc] init] autorelease];

Par rapport à la première méthode, celle-ci ajoute une surcharge supplémentaire par l'utilisation du pool d'autorelease, et dans certaines circonstances, la durée de vie de l'objet sera inutilement prolongée (jusqu'à ce que le pool d'autorelease soit libéré), ce qui augmentera l'empreinte mémoire de votre application.

L'autre mise en œuvre "possible" (selon l'endroit d'où provient l'exemple) est tout simplement :

aController = [[AController alloc] init];

Cependant, il est fortement déconseillé de définir directement une variable d'instance ailleurs que dans une méthode init ou dealloc. Ailleurs, vous devez toujours utiliser des méthodes accesseurs.

Cela nous amène à l'implémentation présentée dans l'exemple de code :

AController *tempAController = [[AController alloc] init];
self.aController = tempAController;
[tempAController release];

Ceci est conforme aux meilleures pratiques depuis :

  • Il évite l'autorelease ;
  • Il rend la sémantique de la gestion de la mémoire immédiatement claire ;
  • Il utilise une méthode accesseur pour définir la variable d'instance.

5voto

Notez également que votre désir de réduire le code à une seule ligne est la raison pour laquelle de nombreuses personnes utilisent Autorelease :

self.aController = [[[AController alloc] init] autorelease];

Bien qu'en théorie, sur l'iPhone, l'autorelease est en quelque sorte plus coûteux (je n'ai jamais entendu d'explication claire à ce sujet) et vous pouvez donc vouloir libérer explicitement l'objet juste après l'avoir assigné ailleurs.

5voto

leviathan Points 5207

Si vous utilisez Xcode, il peut vous aider à détecter ce type de code avec l'analyseur statique. Il suffit de cliquer sur Build >> Build and Analyze

alt text

Cela vous permettra d'afficher un message très utile sur de tels morceaux de code.

alt text

4voto

Ashley Clark Points 6806

Une autre chose à noter est que votre exemple dépend également de la définition @property de aController.

Si elle était définie comme @property (readwrite, retain) id aController; alors votre exemple fonctionne, alors que si elle est définie comme @property (readwrite, assign) id aController; alors l'appel supplémentaire à release causerait la désallocation de votre objet.

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