65 votes

Comment la libération est-elle gérée pour les propriétés de conservation @synthesized?

J'ai quelques questions à propos de synthétisés propriétés en Objective-C. La liste complète suit, mais la question de fond est: Comment le compilateur s'assurer que le ivars pour synthétisés propriétés sont bien sorti, même si mon code ne peut ou peut ne pas inclure la libération des méthodes dans le dealloc?

Note: j'ai décidé de ne pas publier ces questions parce qu'ils sont si étroitement liés, et parce qu'il y a une poignée de questions existantes, que le toucher sur les enjeux individuels sans vraiment rentrer dans le cœur de la question.

Un peu les mêmes questions:


Programme d'installation: Considérons une classe avec une seule propriété:

@interface Person : NSObject
{
    NSString * name;
}
@property (nonatomic, retain) name;
@end

Question #1: Les principes de base de l'affaire:

@implementation Person
@synthesize name;
@end

Avec cette configuration, je suppose qu' name sera automatiquement libéré à chaque fois qu'un Person objet est libéré. Dans mon esprit, le compilateur insère simplement [name release] dans la dealloc méthode comme si j'avais tapé moi-même. Est-ce exact?


Question n ° 2: Si j'ai choisi d'écrire mon propre dealloc méthode de cette classe, et je omettre un appel à l' [name release], cette fuite?

@implementation Person
@synthesize name;
- (void)dealloc { [super dealloc]; }
@end

Question #3: Si j'ai choisi d'écrire mon propre dealloc méthode de cette classe, et je inclure un appel à l' [name release], résultat dans une double version, car @synthesize a déjà pris soin d'elle pour moi?

@implementation Person
@synthesize name;
- (void)dealloc { [name release]; [super dealloc]; }
@end

Question #4: Si j'ai choisi d'écrire mon propre propriété accesseur pour cette classe, mais je ne pas écrire mon propre dealloc méthode, sera name "fuites"?

@implementation Person
@dynamic name;
- (void)setName:(NSString *)newName
{
    [newName retain];
    [name release];
    name = newName;
}
@end

Question #5: j'ai le sentiment (basée sur l'expérience) qu' aucun des scénarios ci-dessus entraînera des fuites ou double-publications, puisque la langue a été conçu pour les éviter. Qui, bien sûr, pose la question du "comment?". Est le compilateur simplement assez intelligent pour garder une trace de chaque cas possible? Si je ne le suit (notez que c'est d'un ridicule exemple, juste pour illustrer mon point de vue):

void Cleanup(id object) { [object release]; }

@implementation Person
@synthesize name;
- (void)dealloc { Cleanup(name); }
@end

Serait-ce tromper le compilateur en ajoutant un autre [name release] de la dealloc méthode?

57voto

KennyTM Points 232647

T1:

Pas de. @synthesize ne modifie pas l' -dealloc pour vous. Vous avez d' -release le name vous-même.

Q2:

Oui, il sera de fuite. Pour la même raison que T1.

Q3:

Non, il ne double-libération. Pour la même raison que T1.

Q4:

Oui, il sera de fuite. Pour la même raison que T1.

Q5:

Non, il ne double-libération. Pour la même raison que T1.


Vous pouvez le vérifier vous-même en substituant -retain et -release et -dealloc rapport à ce qui se passe.

#import <Foundation/Foundation.h>

@interface X : NSObject {}
@end
@implementation X
-(oneway void)release {
        NSLog(@"Releasing %p, next count = %d", self, [self retainCount]-1);
        [super release];
}
-(id)retain {
        NSLog(@"Retaining %p, next count = %d", self, [self retainCount]+1);
        return [super retain];
}
-(void)dealloc {
        NSLog(@"Dealloc %p", self);
        [super dealloc];
}
@end

@interface Y : NSObject {
        X* x;
}
@property (nonatomic, retain) X* x;
@end
@implementation Y
@synthesize x;
- (void)dealloc { [x release]; [super dealloc]; }
@end

int main () {
        NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
        Y* y = [[Y alloc] init];
        X* x = [[X alloc] init];
        y.x = x;
        [y release];
        [x release];
        [pool drain];                                                    
        return 0;
}

En T1, T2 et T4, la dernière -retainCount de x est 1, donc il y a une fuite, et en Q3 et Q5 le dernier -retainCount est 0 et -dealloc est appelé, donc il n'y a pas de fuite.

17voto

Dave Points 2554

À partir de l' Objective-C de la documentation sur les propriétés:

dealloc

Déclaré propriétés fondamentalement prendre la place de la méthode d'accesseur les déclarations; lorsque vous en faire la synthèse de la propriété, le compilateur crée uniquement absents des méthodes accesseurs. Il est aucune interaction directe avec le dealloc méthode-les propriétés ne sont pas libéré automatiquement pour vous. Déclaré, les propriétés, cependant, fournir un moyen utile pour contre-vérifier les la mise en œuvre de votre dealloc méthode: vous pouvez rechercher tous les déclarations de propriété dans votre en-tête fichier et assurez-vous que l'objet les propriétés qui ne sont pas marqués attribuer sont libéré, et ceux marqués d'attribuer sont pas publié.

Il s'agit essentiellement des réponses à toutes vos questions.

8voto

Dan Ray Points 14852

Le simple, et la règle générale: si vous allouer, de conserver, ou de copier un objet, VOUS devez le libérer.

Lorsque vous utilisez l' retain setter sémantique de réglage en @synthesize déclaration, vous êtes de demander au compilateur de créer pour vous un setter qui appelle retain sur l'objet. Rien de plus, rien de moins. Et puisque vous faites de la rétention de l'objet (même si c'est via la magie du code généré automatiquement), vous devez le libérer, et où la libération, il est en -(void)dealloc.

2voto

Adam Points 407

Autre chose à savoir - si vous avez une propriété synthétisée, définir cette propriété sur nil (à l’aide de la syntaxe à points, bien sûr) libérera l’ivar pour vous.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X