Il s'agit d'un artefact d'une version antérieure du runtime Objective-C.
A l'origine, @synthesize
a été utilisé pour créer des méthodes d'accès, 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éfixeraient leurs variables d'instance pour les différencier de leurs propriétés (même si Apple ne veut pas que vous utilisiez des caractères de soulignement, mais c'est une autre question). Vous synthétisez la propriété pour qu'elle pointe vers la variable d'instance. Mais le fait est que, _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
; l'utilisation de la méthode de l'accesseur à la place ressemblerait à ceci (bien que je ne le recommande pas, pour des raisons que je vais expliquer sous peu) :
- (void)dealloc {
self.qux = nil; // [self setQux:nil];
[super dealloc];
}
Cela a pour effet de libérer qux
ainsi que la mise à zéro de la référence. Mais cela peut avoir des effets secondaires fâcheux :
- Vous risquez de déclencher des notifications inattendues. D'autres objets peuvent observer des changements dans
qux
qui sont enregistrés lorsqu'une méthode d'accesseur est utilisée pour le modifier.
- (Tout le monde n'est pas d'accord sur ce point :) Remettre à zéro le pointeur comme le fait l'accesseur peut cacher des erreurs de logique dans votre programme. Si vous accédez à une variable d'instance d'un objet après l'objet a été désalloué, vous faites quelque chose de très mal. En raison de l'approche de l'Objective-C
nil
-Cependant, vous ne le saurez jamais, puisque vous avez utilisé l'accesseur pour définir la valeur de l'option nil
. Si vous aviez libéré la variable d'instance directement et n'aviez pas remis à zéro la référence, l'accès à l'objet désalloué aurait provoqué une forte alerte. EXC_BAD_ACCESS
.
Les versions ultérieures du runtime 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
Cela synthétise en fait une variable d'instance sur Foo
appelé _qux
qui est accessible par des messages getter et setter. -qux
et -setQux:
.
Je ne le recommande pas : c'est un peu désordonné, mais il y a une bonne raison d'utiliser le trait de soulignement ; à savoir, pour se protéger contre un accès direct accidentel à ivar. Si vous pensez que vous pouvez vous faire confiance pour vous rappeler si vous utilisez une variable d'instance brute ou une méthode d'accès, faites-le comme ceci à la place :
@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, il suffit de dire qux
(ce qui se traduit par self->qux
en syntaxe C pour accéder à un membre à partir d'un pointeur). Lorsque vous souhaitez utiliser les méthodes des accesseurs (qui notifieront les observateurs, et feront d'autres choses intéressantes, et rendront les choses plus sûres et plus faciles 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 ici, c'est que les exemples de code et les modèles de code d'Apple sont nuls. Ne vous en servez jamais comme guide pour un style Objective-C correct, et certainement pas comme guide pour une architecture logicielle correcte :)