web-dev-qa-db-fra.com

Propriétés et variables d'instance dans Objective-C

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?

55
Steve Harrison

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 released 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.

29
Mehrdad Afshari

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).

6
stefanB

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 de name = @"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.

3
Peter Hosey

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é.

2
JRT

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
0
Shafraz Buhary