self. ou rien ?

neospiritneospirit Membre
Bonjour à  tous,

je débute en développement sur iPhone et j'ai une interrogation qui semblera toute bête mais quelle est la différence entre :

self.maVariable = 5;

et

maVariable = 5;


La seule différence que j'ai vue c'est que quand je débugge et que je passe le curseur de la souris sur la variable, sa valeur apparait.

Si par contre il y a une autre raison (et je suppose qu'il doit y en avoir une), je veux bien que vous m'expliquiez simplement à  quoi ça sert.

Merci pour votre éclaircissement

neospirit

Réponses

  • DrakenDraken Membre
    23:29 modifié #2
    maVariable = 5;
    


    En utilisant cette formulation tu accèdes normalement à  la variable.

    self.maVariable = 5;
    


    Avec self.uneVariable tu n'accèdes pas à  la variable, mais à  la propriété de même nom. Fait attention à  cela, un self.mavariable mal utilisé peut provoquer des fuites mémoires.

    Ali-qui-ne-dort-jamais pourra t'en dire plus. Moi je vais me coucher !

  • laudemalaudema Membre
    23:29 modifié #3
    Avec maVariable = 5 tu affectes la constante 5 à  la variable d'instance maVariable. Avec self.maVariable = 5 tu déclenches la méthode setMaVariable: qui a été créée pour toi à  la compilation si tu as déclaré maVariable @property et que tu as utilisé la directive @synthesize.

    Si par exemple tu as déclaré dans l'interface
    <br />@property (assign, nonatomic)int maVariable;<br />
    

    alors quand tu fais self.maVariable = 5; tu déclenches
    <br />- (void)setMaVariable(int)unEntier{<br />maVariable = unEntier;<br />}<br />
    

    Avec unEntier égal à  5. Ce qui est bien car tu préserves l'encapsulation en n'accédant pas directement à  maVariable.
    http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17

    En fait tu fais plus que cela car en utilisant les propriétés tu génères aussi une notification au centre de notification et tous les objets intéressés par la valeur de maVariable seront avertis que sa valeur a changé ce qui peut être utile ailleurs dans le code mais surtout dans l'interface.
    http://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/KeyValueCoding/Concepts/BasicPrinciples.html#//apple_ref/doc/uid/20002170-BAJEAIEE

    Donc par le simple fait d'utiliser @property tu utilises plusieurs des "Design Patterns" qui sont au coeur de Cocoa
    http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaDesignPatterns/CocoaDesignPatterns.html#//apple_ref/doc/uid/TP40002974-CH6-SW6
    et tu fais de la programmation objet ;)
  • AliGatorAliGator Membre, Modérateur
    novembre 2010 modifié #4
    Et surtout, dans le cas où ta variable est un entier, et donc que tu as normalement déclaré sa @property en (assign), cela n'impacte pas la gestion mémoire, mais si tu as une autre variable qui elle est déclarée en @property(retain), cela a une incidence bien plus notable, puisque cela effectue le release de la valeur précédente et le retain de la valeur suivante.

    Je n'ai malheureusement pas eu le temps de le finir ces derniers jours (bien que cela fait qques temps que je l'ai commencé mais je suis débordé), mais je suis en train de rédiger un tutoriel sur les @property et donc à  ce sujet. Même si la partie sur la notation pointée (donc la notation "self.toto = x" qui équivaut à  "[self setToto:x]) n'est pas encore rédigée, tu peux déjà  lire l'ébauche ici en attendant que je le termine : il répondra déjà  sans doute à  quelques unes de tes interrogations ;)
  • neospiritneospirit Membre
    23:29 modifié #5
    Bonjour à  tous,

    merci pour vos réponses. Je comprends (presque tout). Je vais lire le tuto de AliGator.

    Dites-moi si je me trompe mais dans le cadre d'une simple utilisation d'une variable "int variable"  pour afficher sa valeur dans un label par exemple, y a-t-il besoin de faire appel à  "self.variable" ?

    Et dans le cas où je n'utilise pas cette syntaxe, où puis-je voir la valeur de "int variable" pendant le debug dans le debugger ?

    Merci encore

    neospirit
  • laudemalaudema Membre
    23:29 modifié #6
    dans 1290097663:


    merci pour vos réponses. Je comprends (presque tout). Je vais lire le tuto de AliGator.

    Excellente idée !

    dans 1290097663:

    Dites-moi si je me trompe mais dans le cadre d'une simple utilisation d'une variable "int variable"  pour afficher sa valeur dans un label par exemple, y a-t-il besoin de faire appel à  "self.variable" ?

    Rien ne t'y oblige, mais attention un "label" est un read only text view et a pour fonction d'afficher une chaà®ne de caractères, il sera incapable d'afficher un nombre, seulement le caractère correspondant à  ce nombre.
    Je ne connais pas assez iOS pour te conseiller dans ces parages, je suppose qu'on y utilise aussi les NSNumberFormatters (enfin je vous le souhaite), si tu peux en glisser un sur ton label alors il sera plus facile d'afficher un nombre via les bindings.
    Sinon un UIALabel a une propriété texte, tu peux donc aussi déclarer un IBOutlet UIATextField *maLabel que tu pourras appeler quand tu en auras besoin dans ton code par un message [maLabel setText:[NSString stringWithFormat:@%i,maVariable]].
    Il y a peut être plus simple mais je ne suis pas qualifié pour te répondre...

    dans 1290097663:

    Et dans le cas où je n'utilise pas cette syntaxe, où puis-je voir la valeur de "int variable" pendant le debug dans le debugger ?

    Que tu utilises ou pas self.maVariable tu peux toujours regarder sa valeur dans le débugger. Si tu as gardé la présentation par défaut de Xcode c'est dans le panneau droit du panneau supérieur, la première colonne "variable" et la seconde "value" http://developer.apple.com/library/ios/#documentation/DeveloperTools/Conceptual/XcodeDebugging/100-Debugging_in_the_Debugger/debugging_in_debugger.html

    Il faut juste déplier le triangle "self" et tu pourras la voir avec toutes les autres variables de ton objet référencé par "self", les bindings n'ont rien à  voir ce ne sont que des méthodes pour accéder de manière KVO-KVC compliant à  ces variables.
  • neospiritneospirit Membre
    23:29 modifié #7
    dans 1290111662:

    Sinon un UIALabel a une propriété texte, tu peux donc aussi déclarer un IBOutlet UIATextField *maLabel que tu pourras appeler quand tu en auras besoin dans ton code par un message [maLabel setText:[NSString stringWithFormat:@%i,maVariable]].

    C'est ce que j'ai fait sur un UILabel, exactement : "decompteLabel.text = [NSString stringWithFormat:@allez encore %d jours avant la retraite, resultatCalcul];"

    Et ça marche bien (je vous rassure, ce n'est pas le vrai texte qui sera dans mon application  :))

    Pour le reste, j'y travaille

    Merci
    neospirit
  • neospiritneospirit Membre
    23:29 modifié #8
    Bonjour,

    après un week end intense de programmation (ma femme ne m'a pas encore quitté mais ça devrait pas tarder  :D), j'ai une application en presque bon état et sans crash.

    J'ai cependant une grosse question. Ayant un peu plus d'expérience dans l'utilisation de XCode (mais pas forcément de la programmation en Cocoa/ObjC), je me pose beaucoup de questions sur la gestion de la mémoire et j'ai besoin de réponses simples. En gros si vous répondez, essayez de vous adresser à  qqun qui n'a jamais programmé  :P. Je saisis les grands principes mais la subtilité.

    Si dans mon .H j'ai cela
    NSInteger id;	<br />NSString *webTitle;<br /><br />@property(nonatomic, retain) NSString *webTitle;<br /><br />
    


    Ensuite dans mon .M j'ai cela
    @synthesize webTitle;<br /><br />self.webTitle = @&quot;Titre de mon site&quot;;<br />id=12;<br /><br />[webTitle release];
    


    Je voulais savoir si cela était la bonne démarche ? Donc pour résumé pas de @propoerty pour un NSInteger ou un int mais par contre pour un NSNumber il en faudrait un.

    Et ensuite pour le NSString, il faut absolument mettre self.webtitle = @";".

    Ayant eu beaucoup de crash dus à  des self manquants et après les avoir mis ça ne crashait plus, je voulais savoir si j'employais donc la bonne méthode.

    Merci
    neospirit
  • CéroceCéroce Membre, Modérateur
    23:29 modifié #9
    En fait, ce qu'il faut comprendre avec les propriétés déclarées retain, c'est que @synthesize génère du code équivalent à  ceci:

    - (NSString *) webTitle<br />{<br />	return webTitle;	<br />}<br /><br />- (void) setWebTitle:(NSString *)newWebTitle<br />{<br />	if(webTitle != newWebTitle)<br />	{<br />		[webTitle release];<br />		webTitle = [newWebTitle retain];	<br />	}	<br />}
    



    Si tu comprends ce code, tu comprends tout: il n'y a pas de magie. ça explique aussi pourquoi écrire [tt]self.webTitle = nil[/tt] relâche la mémoire.


    Ceci dit, ceci est une simplification. D'après nos informations, le code généré serait plutôt celui-ci:

    - (void)setWebTitle:(NSString *)newWebTitle<br />{<br />	[webTitle autorelease];<br />	[self willChangeValueForKey:@&quot;webTitle&quot;];<br />	webTitle = [newWebTitle retain];<br />	[self didChangeValueForKey:@&quot;webTitle&quot;];	<br />}
    


    En effet, appeler un setter génère des notifications Key-Value Observing, et il semble que l'objet soit relâché par l'autorelease pool, et non pas immédiatement.
  • CéroceCéroce Membre, Modérateur
    23:29 modifié #10
    Pour compléter ma réponse.

    Si on écrit:

    webTitle = unAutreObjet.title;
    


    deux erreurs sont commises. En effet :
    - l'objet actuel ne retient pas title. Quand unAutreObjet ne le retiendra plus, webTitle pointera sur un objet qui ne sera plus présent en mémoire => plantage.
    - l'ancien objet pointé par webTitle n'est plus référencé, mais n'est pas désalloué => fuite mémoire.
  • neospiritneospirit Membre
    23:29 modifié #11
    Du coup, vaut-il mieux être en retain ou en assign ?
  • CéroceCéroce Membre, Modérateur
    23:29 modifié #12
    Avec assign, le code généré ressemble à  ça:

    - (void) setWebTitle:(NSString *)newWebTitle<br />{<br />	webTitle = newWebTitle;<br />}
    


    En général, il ne faut pas l'utiliser pour des objets, puisque l'objet n'est pas retenu, et qu'on a donc peu de certitude qu'il sera encore présent en mémoire quand on fera appel à  lui.
    Par contre, pour les types C (c'est à  dire non-objets, comme int, char, float, CGRect, etc.), il faut bien utiliser assign.
  • neospiritneospirit Membre
    23:29 modifié #13
    Pour les int, char, float il faudrait donc faire ça ? :

    @property(nonatomic, assign) CGRect float;<br />@property(nonatomic, assign) int entier;<br />@property(nonatomic, assign) char stringChar;
    


    Du coup, il faut aussi mettre les @synthesize dans le .M pour ces variables ?

    Dans mon appli j'ai un SQLiteManager avec des NSInteger. Je les ai mis en "assign" pour que 3  ViewController tierces puissent accéder à  leurs valeurs. Cela changerait-il donc quelque chose si je les mets en retain comme tout le reste ?
    Et donc aussi mettre des @synthesize sur les NSInteger ?
  • cyranocyrano Membre
    janvier 2011 modifié #14
    mettre un retain sur quelque chose de non dereferencée (qui n'est pas un objet) ne sert a rien. tu penses qu'un "int" ou un "char" a un retainCount?

  • neospiritneospirit Membre
    23:29 modifié #15
    Je n'ai pas dit qu'il fallait mettre un retain sur des int, ou char ou autres objects C. Pour ma part, je ne mettais rien  :D. Et je n'avais pas de retour d'erreur de la part d'Xcode
  • cyranocyrano Membre
    23:29 modifié #16
    @property et @synthesize ne sont que des aides. ils evitent de taper du code "basique".

    Avant il te faut comprendre la notion d'encapsulation et des getter/setter
  • cyranocyrano Membre
    23:29 modifié #18
    un petit conseil.

    utilise les notions que tu maitrises, et pas les "trucs" vu ou lu qque part.

    par exemple, nonatomic, ton application en a t'elle reelement besoin?

  • neospiritneospirit Membre
    23:29 modifié #19
    @muqaddar : très utile ce lien. Je vais l'étudier de plus près.

    @cyrano : euh je sais pas si j'en ai besoin, mais pour l'instant je l'ai vu dans tous les tutos et bout de code que j'ai pu rencontrer, donc par défaut je le mets, mais si y'en  a pas besoin...
  • cyranocyrano Membre
    janvier 2011 modifié #20
    "nonatomic" retire un garde-fou, quand on ne sait pas a quoi servent les garde-fou on les laisse en place. le seul interêt de nonatomic est si ton application a des problemes de performance.

    dans le meme ordre d'idee que le retain sur un int

    Que pensez vous du nonatomic sur un int?  :D
  • CéroceCéroce Membre, Modérateur
    janvier 2011 modifié #21
    Même si je suis 100% d'accord avec toi, il y a beaucoup d'exemples, y compris chez Peupeul, où nonatomic est utilisé. À commencer par les templates Xcode.

    (Mettre une propriété int en retain, ne génère-t-il par une erreur ? C'est le cas pour une propriété en copy).
  • neospiritneospirit Membre
    23:29 modifié #22
    @cyrano : je pense que je vais très clairement laisser nonatomic car quand je vois comment mon appli rame sur le 3G d'un ami alors qu'elle est pas lourde du tout, si je les enlève ça risquerait de pas le faire
  • cyranocyrano Membre
    23:29 modifié #23
    Utilise plutôt instrument pour voir tes hotspots, il m'etonnerai fort que la "lenteur" de ton appli vienne de la.

Connectez-vous ou Inscrivez-vous pour répondre.