Je suis plutôt confus au sujet des propriétés et des variables d'instance dans Objective-C.
Je suis à mi-chemin de la "Programmation Cacao pour Mac OS X" d'Aaron Hillegass et tout est logique. Vous déclareriez une classe quelque chose comme ceci:
@class Something;
@interface MyClass : NSObject {
NSString *name;
NSArray *items;
Something *something;
IBOutlet NSTextField *myTextField;
}
@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSArray *items;
Etant donné que d'autres objets doivent manipuler nos variables d'instance name
et items
, nous utilisons @property
/@synthesize
pour générer des accesseurs/mutateurs pour eux. Dans notre classe, nous n'utilisons pas les accesseurs/mutateurs, nous interagissons simplement avec la variable d'instance.
something
est juste une variable d'instance que nous allons utiliser dans notre classe, et comme personne d'autre n'a besoin de l'utiliser, nous ne créons pas une paire d'accesseurs et de mutateurs pour celle-ci.
Nous devons interagir avec un champ de texte dans notre interface utilisateur. Nous déclarons donc une IBOutlet
pour ce dernier, le connectons et tout est fait.
Tout est très logique.
Cependant, dans le monde de l'iPhone, les choses semblent être différentes. Les personnes déclarent des propriétés pour chaque variable d'instance, des propriétés pour IBOutlets
et utilisent des accesseurs/mutateurs pour interagir avec les variables d'instance dans la classe (par exemple, elles écriraient [self setName:@"Test"]
plutôt que name = @"Test"
).
Pourquoi? Que se passe-t-il? Ces différences sont-elles spécifiques à l'iPhone? Quels sont les avantages de déclarer des propriétés pour toutes les variables d'instance, de déclarer des propriétés pour IBOutlets
et d'utiliser des accesseurs/mutateurs au sein de votre propre classe?
Dans le monde de l'iPhone, il n'y a pas de ramasse-miettes disponible. Vous devrez gérer soigneusement la mémoire avec le comptage de références. Dans cet esprit, considérons la différence entre:
name = @"Test";
et
self.name = @"Test";
// which is equivalent to:
[self setName: @"Test"];
Si vous définissez directement la variable d'instance, sans considération préalable, vous perdrez la référence à la valeur précédente et vous ne pourrez pas ajuster son nombre de rétention (vous devriez l'avoir release
d manuellement). Si vous y accédez via une propriété, elle sera gérée automatiquement pour vous, en même temps que le nombre de rétentions du nouvel objet attribué.
Le concept fondamental n'est pas spécifique à l'iPhone, mais il devient crucial dans un environnement sans le ramasse-miettes.
Les propriétés sont utilisées pour générer des accesseurs pour les variables d'instance, il n'y a pas de magie.
Vous pouvez implémenter les mêmes accesseurs à la main.
Vous trouverez dans le livre de Aaron Hillegass des exemples de 3 stratégies de gestion de la mémoire pour les variables membres. Ils sont assign/copy/retain
. Vous sélectionnez l'un de ceux requis pour une variable donnée.
Je suppose que vous comprenez la gestion de la mémoire dans Objective-c ...
Les accesseurs masquent la complexité et les différences de gestion de la mémoire pour chaque variable.
Par exemple:
name = @"Test"
est une affectation simple, name
contient maintenant la référence à NSString @"Test"
. Cependant, vous pouvez décider d'utiliser copy
ou retain
. Quelle que soit la version de gestion de la mémoire que vous avez choisie, l’accesseur cache la complexité et vous accédez toujours à la variable avec (ou similaire):
[self setName:@"Test"]
[self name]
setName:
peut maintenant utiliser assign/copy or retain
et vous n'avez pas à vous en préoccuper.
À mon avis, les didacticiels iPhone utilisent les propriétés pour aider les nouveaux développeurs à se lancer plus facilement dans la gestion de la mémoire (même s'il est pratique de générer des accesseurs appropriés avec les propriétés plutôt que de les implémenter manuellement à chaque fois).
Cependant, dans le monde de l'iPhone, les choses semblent être différentes. Les personnes déclarent des propriétés pour chaque variable d'instance, des propriétés pour
IBOutlets
et utilisent des accesseurs/mutateurs pour interagir avec les variables d'instance de la classe (par exemple, elles écriraient[self setName:@"Test"]
au lieu dename = @"Test"
).
Ce n'est pas spécifique à l'iPhone. À l'exception des méthodes init
et de la méthode dealloc
, il est recommandé de toujours utiliser vos accesseurs. Le principal avantage, en particulier sur Mac (avec Cocoa Bindings), est que l’utilisation de vos accesseurs signifie des notifications KVO gratuites.
La raison pour laquelle les gens «déclarent des propriétés pour chaque variable d'instance» est probablement que toutes leurs variables d'instance sont des éléments qu'ils souhaitent exposer en tant que propriétés. S'ils souhaitaient garder quelque chose en privé, ils ne déclareraient pas de propriété dans le fichier d'en-tête. (Cependant, ils peuvent en faire une propriété dans une extension de classe du fichier d'implémentation, afin d'obtenir les notifications KVO gratuites susmentionnées.)
Déclarer des propriétés pour les points de vente est excessif, à mon avis. Je ne vois pas pourquoi. Si vous ne créez pas de propriété, le chargeur nib définira la sortie par accès direct à une variable d'instance, ce qui convient parfaitement à cette tâche.
Je suggérerais que le développement moderne a fait une très forte tentative pour identifier, définir et appliquer les meilleures pratiques.
Parmi ces meilleures pratiques, nous trouvons continuité et cohérence.
En plus de discuter de l'utilisation d'accesseurs dans les méthodes init
et dealloc
, les accesseurs doivent généralement être utilisés en permanence (à l'intérieur et à l'extérieur d'une classe) pour les avantages qu'ils offrent, y compris encapsulation résumé et refactorisation) et de faciliter les meilleures pratiques de continuité et de cohérence. Les avantages fondamentaux d'un langage orienté objet entrent en jeu lorsque l'on fait les choses de cette manière et que l'on exploite la totalité des capacités du langage. Le fait d’être toujours cohérent dans le codage est un avantage souvent sous-estimé, comme le confirmera habituellement tout programmeur expérimenté.
Tu peux écrire comme ça
//MyClass.h
@class Something;
@interface MyClass : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSArray *items;
@end
//MyClass.m
@interface MyClass()
@property (nonatomic, strong) IBOutlet NSTextField *myTextField;
@property (nonatomic, strong) Something *something;
@end