Question

Quelle est la différence entre les deux méthodes suivantes pour allouer et initialiser un objet?

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

et

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

La plupart des exemples de pomme utilisent la première méthode. Pourquoi voudriez-vous allouer, init et object puis relâcher immédiatement?

Était-ce utile?

La solution

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 en tant que @ propriété (conserver) :

Votre premier exemple, ligne par ligne:

  1. L'objet est créé par alloc . Son nombre de références est égal à 1.
  2. L'objet est transféré à la méthode setAController: de self , qui lui envoie un message retenue (car la méthode ne savoir d'où vient l'objet), en incrémentant son compte de références à 2.
  3. Le code appelant n'a plus besoin de l'objet lui-même, il appelle donc release , décrémentant le compte de références à 1.

Votre deuxième exemple concerne essentiellement les étapes 1 et 2 mais pas 3, ainsi, le compte de références de l'objet est égal à 2.

La règle est que si vous créez un objet, vous êtes responsable de le libérer lorsque vous avez terminé. Dans votre exemple, le code est exécuté avec tempAController après avoir défini la propriété. Il incombe à la méthode de définition d’appeler retenue si elle a besoin que cet objet reste en place.

Il est important de se rappeler que self.property = foo; dans Objective-C n'est qu'un raccourci pour [self setProperty: foo]; et que le La méthode setProperty: conservera ou copiera les objets selon les besoins.

Si la propriété a été déclarée @property (copy) , 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 égal à 1 même s'il devrait être égal à 0. Vous voudriez donc toujours écrire votre code de la même manière.

Si la propriété a été déclarée @property (assign) , self ne revendique pas la propriété de l'objet et doit être conservée par une autre personne. Dans ce cas, le premier exemple serait incorrect. Ces types de propriétés sont rares et ne sont généralement utilisés que pour les délégués d’objet.

Autres conseils

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). Pourquoi choisir le premier sur le second?

La formulation correcte de ce dernier serait

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

Comparé à l'ancien, cela entraîne une surcharge supplémentaire liée à l'utilisation du pool de libération automatique et, dans certains cas, la durée de vie de l'objet sera inutilement prolongée (jusqu'à ce que le pool de libération automatique soit libérée), ce qui augmentera l'encombrement de la mémoire de votre application.

L’autre "possible" la mise en œuvre (en fonction de la provenance de l'exemple) est simplement:

aController = [[AController alloc] init];

Cependant, la définition directe d'une variable d'instance est fortement déconseillée ailleurs que dans une méthode init ou dealloc. Ailleurs, vous devriez toujours utiliser des méthodes d'accès.

Ceci nous amène ensuite à la mise en oeuvre indiquée dans l'exemple de code:

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

Ceci suit les meilleures pratiques car:

  • Cela évite la libération automatique;
  • La sémantique de la gestion de la mémoire est immédiatement clarifiée;
  • Il utilise une méthode d'accès pour définir la variable d'instance.

Notez également que votre désir de réduire le code à une seule ligne explique pourquoi de nombreuses personnes utilisent Autorelease:

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

Bien qu'en théorie, la libération automatique de l'iPhone coûte un peu plus cher (vous n'avez jamais entendu une explication claire de sa raison) et vous pouvez donc décider de la libérer explicitement juste après avoir affecté l'objet ailleurs.

Si vous utilisez Xcode, cela peut vous aider à détecter ce code avec l’analyseur statique. Il suffit de cliquer sur Build > > Construire et analyser

alt text

Cela vous affichera un message très utile pour ces morceaux de code.

alt text

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

S'il était défini comme @property (lecture-écriture, conservation) id aController; , votre exemple fonctionnera alors que s'il est défini comme @ propriété (readwrite, assign) id aController; alors l'appel supplémentaire à libérer provoquerait la désallocation de votre objet.

Vous pouvez également faire

@property (nonatomic, retain)AController *aController;
...
self.aController= [[AController alloc] init];
[aController release];

avec une propriété retaining, et cela fonctionnerait de la même manière, mais il est préférable d'utiliser l'autre méthode (pour conserver les propriétés) car c'est moins déroutant, ce code donne l'impression que vous affectez aController, puis il est supprimé de la mémoire. alors qu'en fait, setAController le conserve.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top