web-dev-qa-db-fra.com

Quelle est la différence entre les ivars et les propriétés dans Objective-C

Quelle est la différence sémantique entre ces 3 façons d'utiliser les ivars et les propriétés dans Objective-C?

1.

@class MyOtherObject; 
@interface MyObject {
}
@property (nonatomic, retain) MyOtherObject *otherObj;

2.

#import "MyOtherObject.h"
@interface MyObject {
    MyOtherObject *otherObj;
}
@property (nonatomic, retain) MyOtherObject *otherObj;

3.

#import "MyOtherObject.h"
@interface MyObject {
    MyOtherObject *otherObj;
}
80
ennuikiller

Numéro 1 diffère des deux autres en déclarant en avant la classe MyOtherObject pour minimiser la quantité de code vue par le compilateur et l'éditeur de liens et également éviter potentiellement les références circulaires. Si vous le faites de cette façon, n'oubliez pas de mettre #import dans le fichier .m.

En déclarant un fichier @property (et en faisant correspondre @synthesize dans le fichier .m), vous générez automatiquement des méthodes d'accesseur avec la sémantique de la mémoire gérée comme vous le spécifiez. La règle générale pour la plupart des objets est Conserver, mais NSStrings, par exemple, devrait utiliser Copier. Alors que les singletons et les délégués devraient généralement utiliser Assign. Les accesseurs d'écriture manuscrite sont fastidieux et sujets aux erreurs, ce qui évite beaucoup de bugs de frappe et de bêtises.

En outre, déclarer une propriété synthétisée vous permet d'appeler une méthode d'accesseur en utilisant la notation par points comme ceci:

self.otherObj = someOtherNewObject; // set it  
MyOtherObject *thingee = self.otherObj; // get it 

Au lieu de la voie normale de transmission des messages:

[self setOtherObject:someOtherNewObject]; // set it
MyOtherObject *thingee = [self otherObj]; // get it 

Dans les coulisses, vous appelez vraiment une méthode qui ressemble à ceci:

- (void) setOtherObj:(MyOtherObject *)anOtherObject {

    if (otherObject == anOtherObject) {
        return;  
    }

    MyOtherObject *oldOtherObject = otherObject; // keep a reference to the old value for a second
    otherObject = [anOtherObject retain]; // put the new value in  
    [oldOtherObject release]; // let go of the old object
} // set it

…ou ca

- (MyOtherObject *) otherObject {  
    return otherObject;
} // get it

Douleur totale dans le cul, à droite. Maintenant, faites cela pour chaque ivar de la classe. Si vous ne le faites pas correctement, vous obtenez une fuite de mémoire. Il vaut mieux laisser le compilateur faire le travail.

Je vois que Numéro 1 n'a pas d'ivar. En supposant que ce n'est pas une faute de frappe, c'est bien parce que les directives @property/@synthesize vous déclareront également un ivar, dans les coulisses. Je pense que c'est nouveau pour Mac OS X - Snow Leopard et iOS4.

Numéro n'a pas ces accesseurs générés, vous devez donc les écrire vous-même. Si vous voulez que vos méthodes d'accesseur aient des effets secondaires, vous effectuez votre danse de gestion de mémoire standard, comme indiqué ci-dessus, puis effectuez le travail de côté dont vous avez besoin, à l'intérieur de la méthode d'accesseur. Si vous synthétisez une propriété et écrivez la vôtre , alors votre la version a la priorité.

Ai-je tout couvert?

56
willc2

Dans le passé, vous aviez des ivars, et si vous vouliez laisser une autre classe définir ou les lire, vous deviez définir un getter (c'est-à-dire -(NSString *)foo) et un setter (c'est-à-dire -(void)setFoo:(NSString *)aFoo;).

Quelles propriétés vous donnent est le setter et getter gratuitement (presque!) Avec un ivar. Ainsi, lorsque vous définissez une propriété maintenant, vous pouvez définir l'atomicité (voulez-vous autoriser plusieurs actions de configuration à partir de plusieurs threads, par exemple), ainsi qu'assigner/conserver/copier la sémantique (c'est-à-dire, si le setter copie la nouvelle valeur ou enregistrez simplement la valeur actuelle - important si une autre classe essaie de définir votre propriété de chaîne avec une chaîne modifiable qui pourrait être modifiée ultérieurement).

C'est quoi @synthesize Est-ce que. Beaucoup de gens laissent le même nom ivar, mais vous pouvez le changer lorsque vous écrivez votre déclaration de synthèse (c'est-à-dire @synthesize foo=_foo; signifie faire un ivar nommé _foo pour la propriété foo, donc si vous voulez lire ou écrire cette propriété et que vous n'utilisez pas self.foo, vous devrez utiliser _foo = ... - cela vous aide simplement à attraper des références directes à l'ivar si vous ne voulez que passer par le setter et le getter).

Depuis Xcode 4.6, vous n'avez pas besoin d'utiliser le @synthesize instruction - le compilateur le fera automatiquement et par défaut ajoutera le nom de l'ivar avec _.

16
David H