2009-10-15 5 views
1

J'ai l'initialiseur désigné suivante:Initialiseur désigné, conserve les paramètres?

-(id) initWithName:(NSString*)name; 

et l'initialisation par défaut suivant:

-(id) init { return [self initWithName:@"foo"]; } 

Quel genre d'objet ne l'initialiseur désigné reçoit que? Un libéré ou un autoreleased?

donné la initialiseur suivante:

-(id) init { return [self initWithName:[NSString new]]; } 

je recevrais un objet retined. L'initialiseur par défaut n'aurait jamais une chance de le libérer, donc je ne devrais pas le conserver. Maintenant, imaginez au lieu de NSString ce serait une classe qui ne fournit pas un initialiseur de confort (comme -myClassWithParam :). Dois-je fournir un initialiseur de commodité pour permettre la construction en place?

+0

Édition: erreurs de syntaxe supprimées. –

Répondre

3

L'initialisateur (désigné ou non) ne devrait jamais se soucier de la propriété des objets qu'il reçoit comme arguments. S'il veut conserver l'objet, il doit le copier ou le conserver, peu importe d'où vient l'argument. Votre initialiseur désigné initWithName doit copier l'argument name dans son implémentation.

Gestion de la mémoire pour les littéraux NSString est un cas particulier, étant donné que ces objets ne sont jamais libérés et simplement ignorer retain, release et autorelease.

Votre troisième exemple a une fuite, puisque l'objet de chaîne argument nom est jamais sorti.

+3

Plus généralement, aucune méthode ne devrait se soucier de la propriété des objets qu'elle reçoit. La seule chose sur laquelle une méthode devrait s'appuyer (à moins qu'elle ne revendique la propriété) est qu'un paramètre survive pendant la durée de cette méthode. – Chuck

+0

Tout à fait raison. Merci pour cette clarification. –

+0

merci pour cette clarifiaciton, j'ai pensé à cela moi-même, mais je voulais avoir une autre contribution. Comme vous pouvez le deviner, je suis assez nouveau pour obj-c –

0

Vous devriez toujours envoyer un objet autoreleased (ou le libérer après) à vos initialiseurs - les règles de gestion de la mémoire ne changent pas dans ce cas.

Dans votre exemple, je ferais ceci:

-(id) init {return [self initWithName:[[NSString new] autorelease]]]} 

Cela corrigera votre fuite de mémoire et laisser toujours en place CONSTRUIRE.

Cependant, vous n'avez pas besoin retenir supplémentaire en passant par vos initializers - ce que vous faites avec self est très bien. En règle générale, +alloc conserve l'objet une fois et les méthodes -init ne le conservent pas davantage. -init sera appelé à plusieurs reprises que les appels [super init] remonter dans l'arborescence de classe, mais l'objet ne doit être conservé une fois quand il est finalement retourné à l'appelant - +alloc a déjà fait pour vous.

Cependant, commodité méthodes qui ne le font pas contiennent les mots init, copier ou nouveau doit retourner un objet autoreleased. A titre d'exemple:

+(MyObject *)objectWithName:(NSString *)aName { 
    return [[[MyObject alloc] initWithName:aName] autorelease]; 
} 

FWIW, je normalement -init comme mon initialiseur désigné, donc au cas où j'oublie et envoie -init à un objet (ou quelqu'un d'autre fait la même chose), vous n'obtenez un objet corbeille. Par exemple:

-(id)init { 
    if (self = [super init]) { 
     [self setName:[[NSString new] autorelease]]; 

     myReallyImportantiVar = [[NSArray alloc] init]; 
     // etc; 
    } 
    return self; 
} 


-(id)initWithName:(NSString *)aName { 
    if (self = [self init]) { 
     [self setName:aName]; 
    } 
    return self; 
} 

Cela peut être un peu moins efficace (lorsque vous utilisez la setName de -initWithName est appelé deux fois), mais il est beaucoup plus sûr.

+0

'[[NSString new] autorelease]' est une façon obfusquée de dire '[NSString string]' ou simplement '@" "' –

+0

Le code de Johannes ne conserve pas 'self' dans' init'. –

+1

Je n'aime pas vraiment ce que vous faites avec vos initialiseurs. La méthode init avec le moins d'arguments devrait appeler la méthode init avec un argument supplémentaire, où vous passez une variable par défaut (probablement nulle) pour le paramètre supplémentaire. Je me perdrais dans la pratique que vous utilisez, mais ce n'est peut-être qu'une question de style. La façon Cocoa est de le faire en utilisant le mécanisme que j'ai décrit auparavant. Vous pouvez voir un exemple typique dans ma classe de téléchargement: http://github.com/JoostK/Download-Manager/blob/master/JKDownloadManager.m (ligne 61-119) – Joost

Questions connexes