Question

Je suis en train de parcourir toute ma documentation concernant la gestion de la mémoire et je suis un peu confus à propos de quelque chose.

Lorsque vous utilisez @property, cela crée des getters/setters pour l'objet :

.h :@property (conserver, non atomique) NSString *myString

.m :@synthesize maChaîne

Je comprends cela, mais là où je suis confus, c'est l'utilisation de soi.Je vois une syntaxe différente dans différents blogs et livres.J'ai vu:

myString = [NSString alloc] initWithString:@"Hi there"];

ou

self.myString = [NSString alloc] initWithString:@"Hi there"];

Puis dans dealloc je vois :

self.myString = nil;

ou

[myString release];

ou

self.myString = nil;
[myString release];

Sur ce site, quelqu'un a déclaré que l'utilisation de self ajoute un autre incrément au nombre de rétentions ?Est-ce vrai, je n'ai vu ça nulle part.

Les getters/setters automatiques fournis sont-ils automatiquement libérés ?

Quelle est la bonne façon de faire tout cela ?

Merci!

Était-ce utile?

La solution

Si vous n'utilisez pas la syntaxe dot, vous n'utilisez aucun setter ou getter.

La chose suivante est que cela dépend de la manière dont la propriété a été déclarée.

Supposons quelque chose comme ceci:

@property (nonatomic, retain) Article *article;
...
@synthesize article;

Attribuer quelque chose à l'article avec

self.article = [[Article alloc] init];

surchargera l'instance rendue par alloc / init et provoquera une fuite. En effet, l'auteur de l'article le conservera et publiera toute instance précédente pour vous.

Vous pouvez donc le réécrire comme suit:

self.article = [[[Article alloc] init] autorelease];

Faire ceci

article = [[Article alloc] init]; 

est également correct, mais pourrait impliquer une fuite car l'article peut déjà contenir une référence à une instance. Il serait donc nécessaire de libérer la valeur au préalable:

[article release];
article = [[Article alloc] init]; 

Libérer de la mémoire peut être fait avec

[article release];

ou avec

self.article = nil;

Le premier accède directement au champ, aucun setters / getters n'est impliqué. Le second met nul au champ en utilisant un setter. Ce qui libérera l'instance actuelle, s'il y en a une avant de la définir sur nil.

Cette construction

self.myString = nil; 
[myString release];

est tout simplement trop, cela envoie en fait une libération à zéro, ce qui est inoffensif mais également inutile.

Il vous suffit de mapper mentalement le chapeau en utilisant la syntaxe du point en utilisant des méthodes d'accesseur:

self.article = newArticle
// is
[self setArticle:newArticle];

et

myArticle = self.article;
// is
myArticle = [self article];

Quelques suggestions de lecture, tous les documents officiels d'Apple:

Le langage de programmation Objective-C

Guide de programmation de la gestion de la mémoire

Autres conseils

Lorsque vous créez un retain setter, vous créez quelque chose comme ceci :

- (void)setString:(NSString *)someString {
    if (someString != string) {
        [string release];
        [someString retain];
        string = someString;
    }
}

Si vous n'utilisez pas le setter, la nouvelle valeur n'obtient pas cette retenue : vous ne "possédez" pas cette chaîne, et comme ce sont toutes des références, si la chaîne d'origine est libérée, vous pourriez être confronté à une référence nulle, ce qui conduira à un EXC_BAD_ACCESS.L'utilisation du setter garantit que votre classe dispose désormais d'une copie de cette valeur. Donc oui, cela incrémente le nombre de conservations de la nouvelle valeur.(Notez que l'utilisation du getter est une convention de la POO : les étrangers ne devraient pas pouvoir toucher directement l'ivar.Également dans votre getter, vous pouvez modifier la valeur, en renvoyant peut-être un NSArray lorsque votre ivar est un NSMutableArray, par exemple).

Tu ne devrais pas autorelease dans un setter - Apple l'a utilisé dans son exemple de code, mais il faut garder à l'esprit que les setters sont appelés beaucoup - des millions de fois, potentiellement.Tous ces objets vont dans le même pool de libération automatique, donc à moins que vous ne créiez le vôtre et/ou que vous le vidiez régulièrement, vous aurez une tonne d'éléments dans votre pool, tous inutiles mais occupant toujours de la RAM.Il vaut mieux simplement release.

Quant au dealloc, remontez jusqu'à ce setter.Si vous envoyez un release directement, c'est évident : vous libérez cet objet.Mais si tu écris self.string = nil;, ce que tu fais c'est ça :

  1. La valeur nulle n'est pas la même, vous entrez donc la if bloc
  2. Vous libérez l'ancienne valeur : ce que vous voulez faire
  3. Toi retain néant:les messages à zéro ne font rien et vous ne crashez pas
  4. Vous définissez nil, qui ne prend aucune mémoire, sur la chaîne, qui est désormais effectivement vide

Par convention, j'utilise release dans mon dealloc méthode, parce que release semble plus définitif, et dealloc est le dernier appel de méthode que votre objet recevra.j'utilise self.string = nil; dans viewDidUnload et les méthodes d'avertissement de mémoire.

J'espère que cela t'aides!

En plus de la réponse de Nick - les getters / setters synthétisés ne fournissent pas d'autorelease (btw, quelle est la grande idée de faire cela? Eh bien, vous pouvez utiliser getter comme une usine, mais ce n'est pas une méthode courante en Objective C).

Ensuite, dans dealloc, je vois:

self.myString= nil;

ou

[version myString];

ou

self.myString= nil;[myString libération];

Dans dealloc, peu importe la forme de version que vous utilisez.Mais le bon moyen est de supprimer vos champs lors de leur publication :) Je préfère utiliser self.myString = nil; dans dealloc

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