2010-10-28 47 views
0

Je vous écris un cadre et j'ai un objet avec une méthode d'initialisation personnalisée:Appeler dealloc dans init?

@implementation OSDatabase 
@synthesize database; 

// MEM 
- (void)dealloc { 
    sqlite3_close(database); 

    [super dealloc]; 
} 

// INIT 
- (id)initWithDatabasePath:(NSString *)path error:(NSError **)error { 
    if (self = [super init]) { 
    if (!sqlite3_open_v2([path UTF8String], &database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL)) { 
     error = [NSError errorWithDomain:@"OSDatabaseErrorDomain" code:1 userInfo:nil]; 
     [self dealloc]; 
     return nil; 
    } 
    } 

    return self; 
} 

@end 

Est-il sûr d'appeler dealloc à l'intérieur d'une méthode init si une erreur occoured? Je ne suis pas sûr à ce sujet et la gestion de la mémoire est l'une des choses les plus importantes dans ma vie.

Merci.

Répondre

6

Est-il sûr d'appeler dealloc à l'intérieur d'une méthode init si une erreur s'est produite?

N ° envoyer -release comme vous le feriez partout ailleurs. Même dans -init vous ne pouvez pas garantir que le courant compte est conserver 1.


Pourquoi devez-vous jamais envoyer -dealloc sauf dans [super dealloc]-dealloc? La raison en est que vous ne pouvez jamais garantir que quelque chose d'autre a également une référence à votre objet, même dans le -init de votre objet car le [super init] pourrait choisir de conserver l'objet.

Si l'objet renvoyé par [super init] a un nombre de retenue de 1, l'envoi de -release aura le même effet que l'envoi de -dealloc. S'il a un nombre de retenues supérieur à 1, quelque chose d'autre pense qu'il possède l'objet et le libérant le laisserait avec un pointeur invalide, donc -release est toujours la bonne chose à faire.

En outre, ceci:

while([self retainCount] != 0){[self release];} 

entraînerait une boucle infinie et est une idée terrible pour un certain nombre de raisons. Les conserver chefs d'objets ne vont jamais à 0. -release ressemble à quelque chose comme ceci:

- (id)release 
{ 
    if (retainCount == 1) 
    { 
     [self dealloc]; 
    } 
    else 
    { 
     retainCount--; 
    } 
} 

donc la boucle décrémenter le conserver nombre à 1, puis appeler sans cesse dealloc toujours ou jusqu'à ce que la corruption du tas, il a causé conduit à un défaut de seg.

En plus de ne jamais atteindre zéro, la retenue peut être UINT_MAX (par exemple en littéral chaîne ou numérique), ce qui signifie familièrement "cet objet ne doit jamais être désalloué". Si le nombre de retenues est UINT_MAX, -release ne le décrémentera pas.

+0

Qu'en est-il de 'while ([self retainCount]! = 0) {[self release];}'? –

+0

@Koning Baard: ** Non! ** C'est tout aussi mauvais. Je vais éditer ma réponse pour expliquer pourquoi. – JeremyP

+0

"Pile d'excréments" rend à peine justice à quel point c'est ...:) – bbum

2

Par docs, vous ne devez jamais appeler dealloc directement - seulement la méthode [super dealloc] dans votre dealloc personnalisé.

Je pense que l'appel release devrait faire à la place ce qui est attendu (au moins si vous utilisez la méthode init uniquement dans le modèle standard alloc-init).

+0

Au moins dans un exemple de classe «factice» cela fonctionne :) – Vladimir

0

Comme Vladimir a déclaré que vous ne devriez jamais appeler dealloc directement. Lorsque le nombre de retenue d'un objet atteint 0, Cocoa appelle automatiquement dealloc.