Les propriétés déclarées nécessitent-elles une variable d'instance correspondante?


101

Les propriétés d'Objective-C 2.0 nécessitent-elles la déclaration d'une variable d'instance correspondante? Par exemple, j'ai l'habitude de faire quelque chose comme ceci:

MyObject.h

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

MonObjet.m

@implementation
@synthesize name;
@end

Cependant, que se passerait-il si je faisais cela à la place:

MyObject.h

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

Est-ce toujours valable? Et est-ce différent de mon exemple précédent?


Pourquoi le deuxième «MyObject.h» en gras n'est-il pas «MyObject.m»?
Ríomhaire

Réponses:


93

Si vous utilisez Modern Objective-C Runtime (c'est soit iOS 3.x ou supérieur, soit Snow Leopard 64 bits ou supérieur), vous n'avez pas besoin de définir ivars pour vos propriétés dans des cas comme celui-ci.

Lorsque vous @synthesizela propriété, l'ivar sera en effet synthétisé également pour vous. Cela contourne le scénario «fragile-ivar». Vous pouvez en savoir plus sur Cocoa with Love


71

Dans votre interface, vous pouvez déclarer formellement une variable d'instance entre les accolades, ou en @propertydehors des accolades, ou les deux. Dans tous les cas, ils deviennent des attributs de la classe. La différence est que si vous déclarez @property, vous pouvez implémenter using @synthesize, qui code automatiquement votre getter / setter pour vous. Le setter de codeur automatique initialise les entiers et les flottants à zéro, par exemple. SI vous déclarez une variable d'instance et que vous ne spécifiez PAS de variable correspondante @property, vous ne pouvez pas utiliser @synthesizeet devez écrire votre propre getter / setter.

Vous pouvez toujours remplacer le getter / setter auto-codé en spécifiant le vôtre. Ceci est généralement fait avec la managedObjectContextpropriété qui est chargée paresseusement. Ainsi, vous déclarez votre managedObjectContextcomme propriété, mais vous écrivez également une -(NSManagedObjectContext *)managedObjectContextméthode. Rappelez-vous qu'une méthode qui porte le même nom qu'une variable / propriété d'instance est la méthode "getter".

La @propertyméthode de déclaration vous permet également d'autres options, telles que retainet readonly, que la méthode de déclaration de variable d'instance ne fait pas. Fondamentalement, ivarc'est l'ancienne méthode, et l' @propertyétend et la rend plus élégante / plus facile. Vous pouvez vous référer à l'un ou l'autre en utilisant le soi. préfixe, ou pas, cela n'a pas d'importance tant que le nom est unique à cette classe. Sinon, si votre superclasse a le même nom de propriété que vous, alors vous devez dire soit comme self.name ou super.name afin de spécifier de quel nom vous parlez.

Ainsi, vous verrez de moins en moins de personnes déclarer ivars entre les accolades, et plutôt passer à la simple spécification @property, puis à l'action @synthesize. Vous ne pouvez pas faire @synthesizedans votre implémentation sans un correspondant @property. Le synthétiseur sait de quel type d'attribut il s'agit uniquement de la @propertyspécification. L'instruction synthesize vous permet également de renommer les propriétés, de sorte que vous puissiez faire référence à une propriété par un nom (raccourci) à l'intérieur de votre code, mais à l'extérieur dans le fichier .h, utilisez le nom complet. Cependant, avec la saisie semi-automatique vraiment cool que XCode a maintenant, c'est moins un avantage, mais il est toujours là.

J'espère que cela aidera à dissiper toute la confusion et la désinformation qui circulent.


Aujourd'hui, il n'est pas obligatoire d'écrire @synthesize. Alors, comment cette réponse est-elle valable dans ce cas!
raaz

Vous n'êtes pas obligé de déclarer <code> @property ... @ synthesize </code>. L'utilisation de synthétiser vous évite d'avoir à écrire un getter / setter dans votre implémentation. Si vous ne synthétisez pas, vous devez lancer votre propre getter / setter
PapaSmurf

2
@PapaSmurf C'est incorrect. Vous pouvez les utiliser @property, ne pas les utiliser @synthesizeet ne pas les mettre en œuvre vous-même. Le compilateur s'auto- synthesizepour vous, sans avoir à écrire cela plus.
jbrennan

8

cela fonctionne dans les deux sens, mais si vous ne les déclarez pas entre accolades, vous ne verrez pas leurs valeurs dans le débogueur de xcode.


3

De la documentation:

En général, le comportement des propriétés est identique sur les environnements d'exécution modernes et hérités (voir «Versions et plates-formes d'exécution» dans Objective-C Runtime Programming Guide). Il existe une différence essentielle: le runtime moderne prend en charge la synthèse de variables d'instance, contrairement à l'ancien runtime.

Pour que @synthesize fonctionne dans le runtime hérité, vous devez soit fournir une variable d'instance avec le même nom et le même type compatible de la propriété, soit spécifier une autre variable d'instance existante dans l'instruction @synthesize. Avec le runtime moderne, si vous ne fournissez pas de variable d'instance, le compilateur en ajoute une pour vous.


3

Si vous utilisez XCode 4.4 ou version ultérieure, il générera pour vous du code de synthèse de variable d'instance.

Il vous suffit de déclarer les propriétés comme ci-dessous; il générera pour vous du code de synthèse et du code de déclaration de variable d'instance.

@property (nonatomic, strong) NSString *name;

il générera du code de synthèse comme

@synthesize name = _name;

et vous pouvez accéder à la variable d'instance en utilisant _name, c'est similaire à declare

NSString* _name

mais si vous déclarez une propriété en lecture seule, cela ressemble à

@property (nonatomic, strong, readonly) NSString *name;

il générera du code

@synthesize name;

ou

@synthesize name = name; 

Vous devez donc accéder au nom de la variable instantanée sans le préfixe "_" de toute façon que vous pouvez écrire votre propre code de synthèse, puis le compilateur générera du code pour vous. tu peux écrire

@synthesize name = _name;

1

Le langage de programmation Objective-C: directives d'implémentation des propriétés

Il existe des différences dans le comportement de la synthèse des accesseurs qui dépendent de l'exécution (voir aussi «Différence d'exécution»):

  • Pour les environnements d'exécution hérités, les variables d'instance doivent déjà être déclarées dans le bloc @interface de la classe actuelle. Si une variable d'instance du même nom que la propriété existe et si son type est compatible avec le type de la propriété, elle est utilisée. Sinon, vous obtenez une erreur du compilateur.

  • Pour les environnements d'exécution modernes (voir «Versions et plates-formes d'exécution» dans le Guide de programmation d'Objective-C Runtime), les variables d'instance sont synthétisées selon les besoins. Si une variable d'instance du même nom existe déjà, elle est utilisée.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.