2010-09-27 14 views
15

J'essaie de comprendre le but de la directive synthesize avec le remplacement de nom de propriété. Dire que j'ai une interface définie comme suit:Objective-C synthesize la propriété de remplacement de nom de propriété

@interface Dummy ... { 
    UILabel *_dummyLabel; 
} 

@property (retain, nonatomic) UILabel *dummyLabel; 

Et dans le fichier de mise en œuvre, j'ai:

@synthesize dummyLabel = _dummyLabel; 

D'après ce que je comprends, « dummyLabel » est juste un alias de la variable d'instance " _dummyLabel ". Y a-t-il une différence entre self._dummyLabel et self.dummyLabel?

Répondre

24

Oui. self._dummyLabel n'est pas défini, mais _dummyLabel ne l'est pas.

La syntaxe point s'étend aux appels de méthodes simples, elle n'est donc pas spécifique aux propriétés. Si vous avez une méthode appelée -(id)someObject, par exemple dans le cas de , ce sera comme si vous aviez écrit [object someObject];.

self.dummyLabel //works 
self._dummyLabel //does not work 
dummyLabel  //does not work 
_dummyLabel  //works 
[self dummyLabel]; //works 
[self _dummyLabel]; //does not work 
+0

Merci pour la réponse rapide. Hm ... ok, sont [self.dummyLabel setText: @ "..."] et [_dummyLabel setText: @ "..."] faire le quelque chose? Si c'est le cas, je ne vois aucun gros avantage à renommer _dummyLabel en dummyLabel. – Thomas

+0

@Thomas, vous l'avez. –

+1

L'avantage d'avoir un autre nom pour l'ivar que pour la propriété est que vous pouvez facilement voir dans le code lorsque vous accédez à l'un ou l'autre. –

17

Votre compréhension est incorrecte. dummyLabel est le nom de la propriété, et est pas un alias pour la variable d'instance - la variable d'instance est seulement appelé _dummyLabel. Donc, ce qui suit est une instance de Dummy appelé myObject:

  • [myObject dummyLabel] fonctionne
  • myObject.dummyLabel fonctionne
  • [myObject _dummyLabel] échoue
  • myObject._dummyLabel échoue
  • myObject->dummyLabel échoue
  • myObject->_dummyLabel dépend de la visibilité du ivar (@public, @private, @protected)
  • [myObject valueForKey: @"dummyLabel"] fonctionne
  • [myObject valueForKey: @"_dummyLabel"] dépend de la mise en œuvre de +accessInstanceVariablesDirectly (à savoir cela fonctionnera dans le cas par défaut où +accessInstanceVariablesDirectly renvoie YES).
+0

Donc, quand je veux accéder à une variable d'instance dans une méthode, je pourrais utiliser '_dummyLabel = @" blah "' - et cela changerait la valeur directement, plutôt que de passer par un setter? Donc, je pourrais avoir une propriété en lecture seule sans setter, mais toujours le changer en interne en allant directement à l'ivar? Et si je veux utiliser un getter/setter depuis une méthode de la classe, j'utiliserais 'self.dummyLabel'? Ou pourrais-je aussi utiliser 'dummyLabel' directement? –

0

Je ne vois pas de gros avantage de renommer _dummyLabel à dummyLabel

Dans certains ObjC vous runtimes avez du mal à faire des variables d'instance invisible pour les utilisateurs de la classe. Pour eux, coller un préfixe (ou un suffixe) sur vos variables d'instance peut rendre clair (ou plus clair) que vous ne voulez pas que quelqu'un se mêle de vos variables. Cependant, vous ne voulez pas de cette substance sur vos fonctions publiques. Cela vous permet de l'enlever.

Cela peut également être utile si vous devez gérer une ancienne interface avec un ensemble de noms en même temps qu'un nouvel ensemble d'API avec un nouvel ensemble de noms (setLastname vs setSurname).

13

L'avantage d'avoir un autre nom pour la Ivar que pour la propriété est que vous pouvez facilement voir dans le code lorsque vous accédez à l'un ou l' autre - Andre K

I Je ne suis pas capable de trouver un bouton 'commentaire', je dois donc poster comme 'réponse'. Je voulais simplement développer le commentaire d'André - en sachant quand vous utilisez les propriétés synthétisées par rapport à la variable vanille, vous savez (surtout dans le cas de setters) quand une variable est conservée/copiée/libérée automatiquement grâce à votre gentil setter, vs être manipulé à la main.

Bien sûr, si vous faites les choses correctement, vous n'avez probablement pas besoin de l'aide d'un setter pour conserver/libérer des objets correctement! Mais il peut y avoir d'autres scénarios où se référant à vos ivars comme self.ivar au lieu de _ivar peut être utile, comme lorsque vous utilisez des setters/getters personnalisés au lieu des synthétisés par défaut. Peut-être que chaque fois que vous modifiez une propriété, vous souhaitez également la stocker dans NSUserDefaults. Donc, vous pourriez avoir un code comme ceci:

@interface SOUserSettings : NSObject { 

BOOL _autoLoginOn; 

} 

@property (nonatomic, assign) BOOL autoLoginOn; 

@end 

@implementation SOUserSettings 

@synthesize autoLoginOn = _autoLoginOn; 

- (void)setAutoLoginOn:(BOOL)newAutoLoginOnValue { 

    _autoLoginOn = newAutoLoginOnValue; 
    [[NSUserDefaults standardUserDefaults] setBool:_autoLoginOn forKey:@"UserPrefAutoLoginOn"]; 
} 

@end 

Note: Ceci est juste un code d'illustration, il pourrait y avoir mille choses mauvaises avec elle! Alors maintenant, dans votre code, si vous avez une ligne qui indique _autoLoginOn = YES - vous savez qu'il ne va pas être enregistré dans NSUserDefaults, alors que si vous utilisez self.autoLoginOn = YES, vous savez exactement ce qui va se passer.

La différence entre _autoLoginOn et self.autoLoginOn est plus que simplement sémantique.

+0

Excellent, que vous l'avez mentionné! Il y a une différence en effet! –

0

Ancien post, mais je pense qu'il est important de mentionner, qu'il est recommandé d'accéder aux variables via les getters et les setters (donc, avec la notation par points). L'accès direct à un champ (_ivar) est fortement recommandé uniquement lors de l'initialisation.

Il y a un bon article Apple: https://developer.apple.com/library/ios/#documentation/cocoa/conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html

Dernier paragraphe:

Vous devriez toujours accéder aux variables d'instance directement à partir de une méthode d'initialisation, car au moment où une propriété est définie, la Le reste de l'objet n'est peut-être pas encore complètement initialisé. Même si vous ne fournissez pas de méthodes d'accès personnalisées ou si vous connaissez des effets secondaires de dans votre propre classe, une sous-classe future peut très bien remplacer le comportement .