2010-04-30 8 views
2

Je viens de me familiariser avec le CLLocationManager et trouvé plusieurs définitions de classe d'échantillons qui contiennent la méthode init suivante:Pourquoi appeler autorelease pour la définition d'iVar dans la méthode init?

- (id) init { 
    self = [super init]; 

    if (self != nil) { 
     self.locationManager = [[[CLLocationManager alloc] init] autorelease]; 
     self.locationManager.delegate = self; 
    } 
    return self; 
} 

- (void)dealloc { 
    [self.locationManager release]; 
    [super dealloc]; 
} 

Je ne comprends pas pourquoi le iVar serait autoreleased. Cela ne signifie-t-il pas qu'il est désalloué à la fin de la méthode init?

Je suis également perplexe de voir que les mêmes exemples de codes ont la version d'iVar dans la méthode dealloc.

Des pensées? '

Répondre

7

La propriété locationManager est probablement définie avec l'attribut retain.

Fondamentalement, si vous écrivez seulement:

self.locationManager = [[CLLocationManager alloc] init]; 

le poseur latéral gauche self.locationManager conserve une référence au CLLocationManager alloué. Mais la référence CLLocationManager de droite n'est elle-même jamais publiée. Le nombre de retenues pour ce gestionnaire n'atteint jamais zéro et l'objet ne disparaît jamais - cela provoque une fuite de mémoire.

Il y a deux façons de résoudre ce problème. Soit autorelease l'objet alloué que vous avez vu dans le extrait de code que vous avez cité - ou que vous attribuez l'objet affecté à une variable temporaire, conserver la variable temporaire à la propriété locationManager, puis relâchez explicitement la variable temporaire:

CLLocationManager *_temporaryReference = [[CLLocationManager alloc] init]; 
self.locationManager = _temporaryReference; // this is retained 
[_temporaryReference release]; 

Les deux approches sont équivalentes, en termes de gestion de la mémoire. Certains préfèrent cette seconde approche parce qu'ils n'aiment pas attendre que le pool d'autorelease soit «vidé», en particulier sur un appareil à mémoire faible comme un iPhone, et cela permet un contrôle plus serré sur la durée de vie d'un objet.

documentation Apple Objective-C Programming Language explique cet attribut plus en détail.

+0

Salut Alex, encore une fois vous soulevez ma confusion. Merci beaucoup – iFloh

1

Si votre self.locationManager est une propriété qui le conserve, il définit la conservation. En faisant alloc, vous définissez le nombre de retain à +1, ce qui signifie qu'à la fin de la fonction, il est +2. Quand vous dites autorelease, ce sera +1 (à cause de la propriété de rétention). Vous pouvez également le libérer explicitement après l'avoir défini sur la propriété, mais ce que vous faites est moins de code et facile à lire.

+2

Ceci est trompeur. Autorelease ne modifie pas le nombre de rétention. Tout ce qu'il fait est d'ajouter l'objet à un pool autorelease qui enverra une version à l'objet lorsque le pool est drainé.En tout cas, il vaut mieux ne pas même penser à retenir les comptes. Pensez seulement en termes de propriété. L'objet a été obtenu avec la méthode alloc, donc vous possédez l'objet. Vous devez donc le libérer ou le libérer pour renoncer à la propriété lorsque vous en avez fini avec la propriété. La propriété peut être laissée en sécurité pour résoudre ses propres problèmes de propriété. – JeremyP

+0

Merci pour les éclaircissements de votre part. Je pensais que c'était très clair et je suis content que Jeremy retienne la leçon de compte puisque c'est ce que tout se résume à ... – iFloh

+0

Le commentaire de Jeremy est important. Le "autorelease pool" aurait probablement dû s'appeler "autorelease list", puisque les gens voient souvent le mot "pool" et supposent à tort que c'est quelque chose comme le tas ou une zone mémoire qui contient des objets. Autorelease est juste une installation de messagerie retardée. – NSResponder

1

Il existe une alternative sans la variable temporaire ou autorelease:

locationManager = [[CLLocationManager alloc] init]; 

Sans utiliser le self.locationManager vous n'êtes pas appeler la méthode setter de la classe pour cette variable et par conséquent ne pas augmenter le nombre Retain 2. Le compilateur modifie ces affectations en [self setLocationManager: locationManager];. Cela suppose que vous avez prototypé la variable en tant que conserver.

S'il s'agit d'une variable de classe (ce qui est le cas), vous pouvez simplement effectuer l'affectation. On peut se demander s'il s'agit d'une bonne pratique de codage mais, à mon avis, cela dépend de l'endroit où il se trouve dans l'initiation de la classe.

Questions connexes