Duplicate possible:
Comment un trait de soulignement devant une variable dans une classe cacao objective-c fonctionne-t-il?
Lors de la création d'un nouveau projet dans Xcode 4, le code standard ajoute un caractère de soulignement lorsqu'il synthétise les ivars du fichier d'implémentation en tant que:
@synthesize window = _window;
ou:
@synthesize managedObjectContext = __managedObjectContext;
Quelqu'un peut-il me dire ce qui est accompli ici? Je ne suis pas un nube complet, mais c’est un aspect de l’objectif-C que je ne comprends pas.
Un autre point de confusion; dans l'implémentation de délégué d'application, après avoir synthétisé la fenêtre iVar comme ci-dessus, dans l'application didFinishLaunchingWithOptions: méthode, les ivars window et viewController sont référencés à l'aide de self:
self.window.rootViewController = self.viewController
[self.window makeKeyAndVisible];
mais dans la méthode dealloc c'est _window ou _viewController
Merci
Il s'agit d'un artefact d'une version précédente du moteur d'exécution Objective-C.
À l'origine, @synthesize
était utilisé pour créer des méthodes d’accesseurs, mais le runtime exigeait toujours que les variables d’instance soient instanciées explicitement:
@interface Foo : Bar {
Baz *_qux;
}
@property (retain) Baz *qux;
@end
@implementation Foo
@synthesize qux = _qux;
- (void)dealloc {
[_qux release];
[super dealloc];
}
@end
Les gens préfixent leurs variables d'instance pour les différencier de leurs propriétés (même si Apple ne veut pas que vous utilisiez des traits de soulignement, mais c'est une autre affaire). Vous synthétisez la propriété pour pointer sur l'instance variable, mais le point est, _qux
est une variable d’instance et self.qux
(ou [self qux]
) est le message qux
envoyé à l'objet self
.
Nous utilisons la variable d'instance directement dans -dealloc
; En utilisant plutôt la méthode d'accès, cela ressemblerait à ceci (bien que je ne le recommande pas, pour des raisons que j'expliquerai bientôt):
- (void)dealloc {
self.qux = nil; // [self setQux:nil];
[super dealloc];
}
Cela a pour effet de libérer qux
, ainsi que de mettre à zéro la référence. Mais cela peut avoir des effets secondaires regrettables:
qux
, qui sont enregistrées lorsqu'une méthode d'accès est utilisée pour la modifier.nil
d'Objective-C, vous ne le saurez jamais, vous avez utilisé l'accesseur pour définir sur nil
. Si vous aviez libéré la variable d'instance directement et que la référence n'avait pas été réinitialisée, l'accès à l'objet désalloué aurait provoqué un fort EXC_BAD_ACCESS
.Des versions ultérieures du moteur d'exécution ont ajouté la possibilité de synthétiser des variables d'instance en plus des méthodes d'accès. Avec ces versions du runtime, le code ci-dessus peut être écrit en omettant les variables d'instance:
@interface Foo : Bar
@property (retain) Baz *qux;
@end
@implementation Foo
@synthesize qux = _qux;
- (void)dealloc {
[_qux release];
[super dealloc];
}
@end
Ceci synthétise en fait une variable d’instance sur Foo
appelée _qux
, auquel on accède par les messages getter et setter -qux
et -setQux:
.
Je recommande contre cela: c'est un peu brouillon, mais il y a une bonne raison d'utiliser le trait de soulignement; à savoir, pour protéger contre un accès direct accidentel ivar. Si vous pensez pouvoir vous souvenir que vous utilisez une variable d'instance brute ou une méthode d'accès, procédez comme suit:
@interface Foo : Bar
@property (retain) Baz *qux;
@end
@implementation Foo
@synthesize qux;
- (void)dealloc {
[qux release];
[super dealloc];
}
@end
Ensuite, lorsque vous voulez accéder directement à la variable d’instance, dites simplement qux
(ce qui se traduit par self->qux
en syntaxe C pour accéder à un membre à partir d’un pointeur). Lorsque vous souhaitez utiliser des méthodes d'accesseurs (qui avertissent les observateurs, effectuent d'autres tâches intéressantes et rendent les opérations plus sûres et plus simples en ce qui concerne la gestion de la mémoire), utilisez self.qux
([self qux]
) et self.qux = blah;
([self setQux:blah]
).
Ce qui est triste, c’est que le code exemple et le code modèle d’Apple sont nuls. Ne l'utilisez jamais comme guide pour le style correct Objective-C et certainement jamais comme guide pour une architecture logicielle appropriée. :)
Voici une autre raison. Sans souligner les variables d'instance, vous obtenez souvent un avertissement avec les paramètres self.title = title
et self.rating = rating
:
@implementation ScaryBugData
@synthesize title;
@synthesize rating;
- (id)initWithTitle:(NSString *)title rating:(float)rating {
if (self = [super init]) {
self.title = title; // Warning. Local declaration hides instance variable
self.rating = rating; // Warning. Local declaration hides instance variable
}
return self;
}
@end
Vous évitez les avertissements en soulignant les variables d'instance:
@implementation ScaryBugData
@synthesize title = _title;
@synthesize rating = _rating;
- (id)initWithTitle:(NSString *)title rating:(float)rating {
if (self = [super init]) {
self.title = title; // No warning
self.rating = rating; // No warning
}
return self;
}
@end
dans l'application didFinishLaunchingWithOptions: méthode, les ivars viewController window et sont référencés à l'aide de self
Non, ils ne sont pas. Ce sont des références aux propriétéswindow
et viewController
. C'est le point du trait de soulignement, pour que ce soit plus clair lorsque la propriété est utilisée (pas de soulignement) et quand l'accès direct à ivar (avec soulignement).
Oui, c'est juste pour différencier la référence d'objet. C'est-à-dire que si l'objet est référé directement, utilisez-le avec un trait de soulignement, sinon utilisez self pour faire référence à l'objet.