Fonctionnement de l'attribut (copy) pour une @property

flo@flyflo@fly Membre
février 2013 modifié dans API AppKit #1
Bonsoir à  tous,



Je dois énerver avec mes questions somme toutes de débutant mais voici le problème auquel je suis confronté, voici mon interface :


@interface XYZPerson : NSObject<br />
@property (copy) NSString *firstName;<br />
@property (copy) NSString *lastName;<br />
@property (copy) NSDate *yearOfBirth;




Mon code dans la fonction main :
NSMutableString *nameString = [NSMutableString stringWithString:@&quot;Florian&quot;];<br />
		XYZPerson *person = [[XYZPerson person] initWithFirstName:nameString lastName:@&quot;Courtial&quot; yob:nil];<br />
		[person sayHello];<br />
		[nameString setString:@&quot;no&quot;];<br />
		[person sayHello];




Dans le cas où ma fonction d'initialisation est égale à  ça :


-(id)initWithFirstName:(NSString *)firstName lastName:(NSString *)lastName yob:(NSDate *)yob {<br />
	self = [super init];<br />
  <br />
	if (self) {<br />
		[self setFirstName:firstName];<br />
		_lastName = lastName;<br />
		_yearOfBirth = yob;<br />
	}<br />
  <br />
	return self;<br />
}




J'obtiens ce résultat normal :


2013-02-04 22:18:30.898 ObjcAppleTraining[994:303] Hello Florian Courtial<br />
2013-02-04 22:18:30.900 ObjcAppleTraining[994:303] Hello Florian Courtial




Mais dans le cas ou ma fonction d'intialisation est égale à  ça :


-(id)initWithFirstName:(NSString *)firstName lastName:(NSString *)lastName yob:(NSDate *)yob {<br />
    self = [super init];<br />
   <br />
    if (self) {<br />
	    _firstName = firstName;<br />
	    _lastName = lastName;<br />
	    _yearOfBirth = yob;<br />
    }<br />
   <br />
    return self;<br />
}<br />




J'obtiens alors ce résultat :


2013-02-04 22:21:33.175 ObjcAppleTraining[1014:303] Hello Florian Courtial<br />
2013-02-04 22:21:33.177 ObjcAppleTraining[1014:303] Hello no Courtial




J'ai l'impression que
_firstName = firstName;
n'entraine pas la copy à  l'inverse de
[self setFirstName:firstName];
.



Quelqu'un aurait une explication ?

Réponses

  • 'flo@fly' a écrit:
    J'ai l'impression que
    _firstName = firstName;
    
    n'entraine pas la copy à  l'inverse de
    [self setFirstName:firstName];
    
    . Quelqu'un aurait une explication ?


    Dans le premier cas tu affectes une variable [font=courier new,courier,monospace]_firstName[/font] et dans le second cas tu affectes une propriété [font=courier new,courier,monospace]firstName[/font] qui a l'attribut copy, donc une copie a lieu.

    En fait le code fait exactement et TRàˆS précisément ce que tu as codé. Ce qui est un peu énervant parfois, je le concède. On aimerait bien que le code devine ce que l'on veut faire ...
  • AliGatorAliGator Membre, Modérateur
    En effet, c'est le cas.



    _firstName est une variable d'instance (automatiquement générée lorsque tu as écrit la @property : par défaut une variable d'instance du même nom mais précédée d'un underscore est générée pour chaque @property, sauf si tu spécifies explicitement la directive @synthesize ou @dynamic pour spécifier autrement).

    Accéder à  la variable d'instance directement fait directement une affectation pure et simple. Aucun appel de méthode, directement une affectation. Comme si tu avais une variable "int i" et que tu faisais "i = 5" quoi.



    firstName à  l'inverse est une propriété. Ecrire "self.firstName = x", ou "[self setFirstName:x]" (les 2 notations sont équivalentes) va appeler le setter de la propriété (la méthode setFirstName, donc). Ecrire "x = self.firstName" ou "[self firstName]" (les 2 notations sont équivalentes) va appeler le getter de la propriété.

    Si tu ne les as pas surchargées toi-même, le getter "-(NSString*)firstName" et le setter "-(void)setFirstName:(NSString*)" vont être implémenté automatiquement (C'est ce qu'on appelle la synthèse automatique des accesseurs des propriétés, ou "Automatic Property Synthesis"), en respectant les attributs (retain/strong/weak/copy/nonatomic/readonly/readwrite/...) que tu as mis sur la déclaration de ta @property. Donc si tu as mis "(copy)", l'implémentation implicite de "-(void)setFirstName(NSString*)newName" va en somme faire _firstName = [newName copy] (plus quelques autres trucs, comme gérer le KVO, releaser la mémoire de l'ancienne valeur, etc)





    En pratique, je te conseillerai de ne jamais manipuler la variable d'instance (_firstName) directement (de toute façon je ne sais pas ce que te disent tes bouquins pour apprendre l'Objective-C, mais il n'est pas nécessaire de déclarer les variables d'instance associées aux propriétés, le compilateur le fait pour toi tout seul comme un grand, donc la déclaration des @property suffit -- et avec les dernières versions du compilateur même plus besoin de @synthesize explicite non plus, et avec ARC plus besoin de dealloc non plus...), de toute façon tu n'as en pratique même pas à  connaà®tre l'existence de cette variable d'instance _firstName...



    Le mieux est plutôt de toujours manipuler les propriétés, donc avec self.firstName = xxx (ou [self setFirstName:xxx] si tu préfères cette notation à  la notation pointée, c'est toi qui voit). Comme ça tu es assuré que les getters et setters sont appelés dans tous les cas, et qu'ils se chargent de gérer la mémoire correctement, comme tu l'as défini dans la déclaration de ta @property (copy ou retain ou assign, etc). En évitant de manipuler les variables d'instance directement tu éviteras d'avoir à  gérer toi-même la mémoire (ici le "copy") puisqu'en appelant les propriétés (self.firstName et pas _firstName donc) ça se fait tout seul (c'est tout l'intérêt d'avoir des setters/getters justement)
  • Oui je me disais qu'une affectation ne faisait qu'affecter alors qu'un getter affecte et réalise d'autre traitements. Je comprend mieux pourquoi apple met ça dans sa doc :


    _instanceVariableForCopyProperty = [aString copy];
    




    Par contre je pensé qu'a l'affectation simple comme ceci :


    _firstName = firstName;
    




    Le compilateur se disait seul, "tiens on affecte faisons une copie". Mais non en faite ^^

    Car apple dit que l'on peut utiliser _variable mais que d'habitude on utilise plutôt self.variable ou des accesseurs, donc je pensais que ces trois solutions étaient identiques.
  • [font=courier new,courier,monospace]self.variable[/font] est tout à  fait équivalent à  l'utilisation des accesseurs/mutateurs.
Connectez-vous ou Inscrivez-vous pour répondre.