2009-10-11 5 views
3

Je suis un livre sur le développement de l'iPhone et il y a un modèle particulier que je vois dans l'exemple de code qui n'a pas beaucoup de sens pour moi. Chaque fois qu'une propriété est définie, ils affectent d'abord un pointeur à la nouvelle valeur de la propriété, puis définissent la propriété sur le pointeur, puis relâchent le pointeur. Exemple:Variables temporaires inutiles lors de la définition des valeurs de propriété?

Interface:

@interface DoubleComponentPickerViewController : UIViewController { 
    NSArray *breadTypes; 
} 

@property(nonatomic, retain) NSArray *breadTypes; 

@end 

Méthode de classe:

- (void)viewDidLoad { 
    NSArray *breadArray = [[NSArray alloc] initWithObjects:@"White", @"Whole Wheat", @"Rye", @"Sourdough", @"Seven Grain", nil]; 
    self.breadTypes = breadArray; 
    [breadArray release]; 
} 

Y at-il raison de le faire au lieu de faire simplement ce qui suit?

- (void)viewDidLoad { 
    self.breadTypes = [[NSArray alloc] initWithObjects:@"White", @"Whole Wheat", @"Rye", @"Sourdough", @"Seven Grain", nil]; 
} 

Merci pour la lumière qui sera sans aucun doute être versé :)

+0

quel livre vous lisez par curiosité? –

+0

Début iPhone 3 Développement (http://www.amazon.com/Beginning-iPhone-Development-Exploring-SDK/dp/1430224592/ref=sr_1_1?ie=UTF8&s=books&qid=1255312956&sr=8-1). C'est plutôt bien, mais il y a des erreurs et des omissions assez évidentes dans presque tous les chapitres que j'ai lus. Rien de trop sérieux mais assez pour me demander quel effort ils ont mis dans la mise à jour pour la deuxième édition. – Kenny

Répondre

9

Je vais essayer de l'expliquer d'une manière différente. Une méthode qui a alloc, copy ou new dans son nom allouera de la mémoire pour un objet, et donne la propriété de cet objet à l'appelant, et il est de la responsabilité de l'appelant de libérer cette mémoire.

Dans votre méthode viewDidLoad, vous appelez une méthode qui vous donne la propriété d'un objet. C'est votre responsabilité de le libérer. Cependant, avant de faire cela, vous voulez faire quelque chose avec lui - après tout, c'est pourquoi vous l'avez alloué, pas seulement pour le libérer, mais pour faire quelque chose d'utile avec. Peu importe ce que vous voulez faire avec, vous devez le relâcher (ou le relancer automatiquement *). Dans ce cas, votre utilisation de l'objet est de le passer à self.breadTypes. self.breadTypes peut ne pas ressembler à une méthode, mais c'est (c'est un setter). Vous lui passez breadArray. Il fait ce qu'il faut pour ça. Il peut être conservé pour une utilisation ultérieure, ou il peut en copier des informations ou en faire une copie. Votre viewDidLoad ne s'en soucie pas vraiment. Il suppose que self.breadTypes fait ce dont il a besoin et quand il revient, il ne se soucie pas de ce que vous faites avec breadArray. Et ce que vous faites avec, c'est ce que vous avez à faire avec tout ce que vous possédez - relâchez (ou autorelease * it). C'est pourquoi vous devez utiliser la variable temp, breadArray. Vous ne pouvez pas tout à fait publier les résultats de alloc sur la même ligne, puisque l'objet ne se libéré avant self.breadTypes peut avoir à lui:

self.breadTypes = [[[NSArray alloc] initWithObjects:@"White", ..., nil] release]; 

Ainsi, vous êtes obligé d'assigner à une variable temporaire, passer à self.breadTypes, puis libérez l'objet qui est enregistré dans breadArray.

Maintenant, vous pouvez essayer de le faire de cette façon afin de ne pas utiliser une variable temporaire:

- (void)viewDidLoad { 
    self.breadTypes = [[NSArray alloc] initWithObjects:@"White", @..., nil]; 
    [self.breadTypes release]; 
} 

mais ce n'est pas très efficace puisque vous appelez encore une autre méthode (comme self.breadTypes getter) dont vous n'avez pas vraiment besoin si vous venez de stocker la valeur dans une variable temp.

* Maintenant, comme un répondeur dit, vous pouvez utiliser autorelease pour une version alternative:

- (void)viewDidLoad { 
    self.breadTypes = [[[NSArray alloc] initWithObjects:@"White", ..., nil] 
         autorelease]; 
} 

Apple nous pousse à réfléchir à deux fois si nous voulons utiliser autorelease par rapport à la libération. Autorelease peut ne pas être le meilleur choix pour chaque situation. Personnellement, je tiens à nettoyer après moi-même dès que possible, et ne pas utiliser inutilement la libération automatique. objets autoreleased se libérés à la fin de l'exécution de la boucle d'exécution, par exemple, peu après les retours viewDidLoad. Vous devriez lire un peu plus sur autorelease (et la gestion de la mémoire sur l'iPhone qui est légèrement différent de celui MacOS X Cocoa), comme je suis tout simplifie à l'extrême.

BTW: Si vous retain un objet, vous en assumez la propriété, et vous aurez la même responsabilité encore, à release une fois que vous avez fini avec elle.

+0

Merci d'avoir pris le temps d'écrire tout cela. C'était très utile. – Kenny

3

Oui. Ces méthodes allouent les variables de sorte qu'elles doivent être libérées. Le fait que la propriété possède un attribut retain signifie que lorsque vous dites , le compilateur génère en fait un setBreadTypes qui libère correctement le membre breadType actuel et conserve le nouveau. Ainsi, votre fonction ne doit pas conserver la variable alloc 'ed.

Vous pouvez cependant écrire:

- (void)viewDidLoad { 
    self.breadTypes = [[[NSArray alloc] initWithObjects:@"White", 
           @"Whole Wheat", @"Rye", @"Sourdough", 
           @"Seven Grain", nil] 
         autorelease]; 
} 

Vous voulez rafraîchir Cocoa Memory Management

+0

Merci pour la bonne réponse. Je vais lire le lien fourni. – Kenny

Questions connexes