Question sur la facon de déclarer une variable avec un _ devant

Une question concernant la déclaration de pointeur ( variable ), dans l'interface les variables sont déclaré avec un _ devant leur nom, puis dans le @property on l'ecrit sans le _ et enfin dans le .m on synthetise en faisant une égalité.

Estce que quelqu'un peut m'expliquer 'linteret de cette facon de faire? pourquoi utiliser le _ et ne pas directement mettre le nom de la variable et l'utiliser?

fichier.h

@interface ; .... {

        UINavigationController * _navigationController;
DetailViewController * _DetailController;
}

@property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
@property (nonatomic, retain) IBOutlet DetailViewController *detailViewController;

fichier.m:

@synthesize navigationController=_navigationController;
@synthesize detailViewController=_DetailController;

Réponses

  • 22:01 modifié #2
    l'underscore devant les ivars est utilisé par Apple pour déclarer des variables privées.
    Il ne faut absolument pas utiliser un simple _ pour déclarer les tiennes.
    De plus, ne jamais mettre de majuscule sur la première lettre, même après un underscore.
    Personnellement, j'utilise un double underscore. Mais chacun voit midi à  sa porte
  • 22:01 modifié #3
    Merci j'ai une 2ieme petite question:
    au debut d'un fichier quand on met
    @class xxx
    @class yyy
    etc etc
    cela veut dire que l'on fait appel a ces class pour pouvoir utiliser leur fonction comme on ferait un include en php ou alors cela veut dire que les fonctions que l'on va definir dans ce fichier feront partie des class décrites?
  • 22:01 modifié #4
    Pour ta réponse plus haut je viens de tomber sur une discussion a ce sujet, du coup je ne sais quoi en penser?!

    http://pommedev.mediabox.fr/optimisation-refactoring-trucs-et-astuces/le-point-sur-les-conventions-de-noms-de-variables/10/?wap2
  • muqaddarmuqaddar Administrateur
    22:01 modifié #5
    Moi j'ai l'habitude de mettre des _ même sur les ivars non privées.

    Mais comme l'a dit ldesroziers, chacun fait comme il veut...
  • 22:01 modifié #6
    mais ce que je ne comprends pas c'est le pourquoi du comment?
    pourquoi mettre un _ devant une variable, quel est l'interet en fait?
  • muqaddarmuqaddar Administrateur
    22:01 modifié #7
    C'est très simple, si c'est UNE convention, ou si c'est TA convention, tu sais qu'à  chaque fois que tu tapes ou que tu croises une _ivar dans ton code, c'est une ivar, pour la différencier des variables de méthodes par exemple.
  • 22:01 modifié #8
    j'ai cherché sur le net mais je comprends pas trop la difference entre variable normales, d'instances et de classes

    Comment s'appelle la variable par exemple comme un int i que l'on va utilise dans une boucle for?

    une variable globale comme en php par exemple c'est une variable de classe?

    je suis perdu  B)
  • juin 2011 modifié #9
    int i pour une boucle for, j'appellerai ça une variable normale.. Je connais pas le terme exacte. J'appelle ça "variable".
    Une variable d'instance, plus communément appelée "iVar" est une variable que tu déclares dans ton fichier header (.h)

    Edit: voir réponse de Céroce plus bas
  • CéroceCéroce Membre, Modérateur
    juin 2011 modifié #10
    Variable globale
    variable accessible dans tout le fichier .m. On peut aussi les rendre globales à  toute l'application (si on est suicidaire).

    Variable d'instance
    variable déclarée entre les accolades de l'interface d'une classe. Chaque instance de la classe en possède ses propres copies, d'où le nom.

    Variable locale
    variable déclarée dans une méthode ou une fonction, et inaccessible ailleurs.

    Variable de classe
    n'existe pas en ObjC.
  • juin 2011 modifié #11
    Pour les variables de classe j'avais effectivement lu que ça n'existait pas, mais qu'en est-il de cet exemple (trouvé sur le net):
    <br />// TestClass.h <br />@interface TestClass : NSObject <br />{ <br />} <br />+ (NSString)instanceCount; <br />@end <br />// TestClass.m <br />static NSString * instanceCount = nil; <br />@implementation TestClass : NSObject <br />+ (NSString)instanceCount { <br />&nbsp; &nbsp; return instanceCount ? instanceCount : @&quot;0&quot;; <br />} <br />@end <br />
    


    Est-ce qu'on peut considérer "instanceCount" comme une variable de classe du fait qu'il peut être récupéré via une méthode de classe?


    Pour revenir au sujet principal, il faut surtout faire attention avec les méthodes privées. Ne jamais mettre de _ devant le nom d'une méthode.
  • CéroceCéroce Membre, Modérateur
    22:01 modifié #12
    Oui, ça correspond tout à  fait fonctionnellement aux variables de classe qu'on trouve en Java. Note que c'est implémenté grâce à  une variable globale (au fichier .m).
  • 22:01 modifié #13
    dans 1308053917:

    Pour revenir au sujet principal, il faut surtout faire attention avec les méthodes privées. Ne jamais mettre de _ devant le nom d'une méthode.


    Merci pour vos réponses c'est deja bcp plus clair dans mon esprit, seulement methode privées, qu'est-ce que cela signifie ?
    Car dans ta premiere reponse tu me dis :

    "l'underscore devant les ivars est utilisé par Apple pour déclarer des variables privées.
    Il ne faut absolument pas utiliser un simple _ pour déclarer les tiennes."

    donc _ c'est généralement devant les variables et les methodes PRIVEES d'apple ?

    si j'ai bien compris une methode privée c'est une methode definie dans une classe ou un protocole d'apple comme par exemple la méthode initwithstring?

    j'ai peur de confondre avec les variables privé avec @private devant..?
  • AliGatorAliGator Membre, Modérateur
    22:01 modifié #14
    En fait c'est normal que tu confondes les deux, c'est un abus de langage que j'ai fait au dessus.

    D'après les conventions Apple, sont à  réserver pour les variables internes à  Apple (on aurait dû parler de "variables d'instances internes à  Apple" plutôt que de variables "privées" car là  on ne parlais pas de "privées" dans le sens "périmètre d'accessibilité façon @public/@private/@protected"; mais dans le sens "réservées par Apple").
    Apple pouvant, au gré des versions du SDK, rajouter des variables d'instances (que tu ne vois pas forcément car toi pour utiliser une classe Apple comme NSArray ou autre, tu consultes bien souvent la doc, et pas les .h de ces classes, mais si tu consultes genre NSArray.h tu pourras voir qu'il y a bien des variables d'instance, auxquelles toi tu n'accèdes jamais directement, mais qui sont utilisées par Apple quand ils ont codé la classe pour diverses raisons selon leur implémentation). Du coup, comme tu ne sais pas ce qu'Apple va se permettre de rajouter comme variable "en interne" à  ses propres classes, ils ont pris comme convention de commencer leurs variables par des "_" et te déconseillent du coup d'utiliser ce "_" au début des tiennes, pour éviter les conflits.
    Maintenant si tu déclares une variables commençant par un "_" mais dans une classe à  toi qui dérive directement de NSObject, et si en plus la variable en question a un nom très spécifique, comme "_blabla", tu as peu de chances d'avoir des problèmes. Par contre si tu l'appelles "_delegate", y'a des chances qu'Apple utilise aussi ce nom là  un jour... Si tu dérives non pas de NSObject mais d'une classe plus spécifique (comme NSArray ou NSString ou UIButton ou UIView, ...) là  tu as plus de chances d'avoir des conflits.

    Après en pratique, il se trouve que nombreux sont ceux (moi le premier, mea culpa, bien que je me soigne sur ce point :P) qui utilisent quand même le "_" au début du nom de leurs variables d'instance. Le but est de pouvoir différencier facilement, grâce à  cette pseudo-convention de nommage, les variables locales (déclarées au sein d'une fonction et qui n'existent pas en dehors de cette fonction) des variables d'instance (déclarées dans le .h et qui existent tout au long de la vie de l'instance de la classe).

    C'est aussi utile pour distinguer une variable d'instance servant de "stockage" pour une propriété, de la propriété elle-même. Par exemple si tu déclares une variable d'instance (une ivar) "NSString* toto" et une propriété éponyme "@property NSString* toto", certes parce qu'elle a le même nom après tu peux juste mettre "@synthesize toto" et cela va générer automatiquement le getter et setter de la propriété toto en se servant de la ivar "toto" comme variable de stockage. Mais du coup dans ton code, tu peux facilement être amené à  écrire [tt]toto = [NSString stringWithFormat:@Toto a %d ans,age];[/tt] au lieu de [tt]self.toto = [NSString stringWithFormat:@Toto a %d ans,age];[/tt]... ce qui aurait de graves conséquences au niveau de la gestion de la mémoire (le premier affectant la variable d'instance, directement, alors que le second appellant la propriété, et donc son setter (vu qu'on fait une affectation), qui va s'occuper de la gestion de la mémoire (faire le release de la valeur précédente et le retain de la nouvelle, si ta @property a été déclarée en "(retain)", typiquement).
    Alors que si tu nommes ta variable d'instance "_toto" et ta propriété "toto" et que tu écris [tt]@synthesize toto = _toto;[/tt] au moins tu distingues la ivar ("_toto") de la propriété ("toto") et tu as bcp moins de chances de confondre les deux !
    Après, en pratique, l'idéal serait alors d'utiliser une notation autre que "_" pour ne pas risquer les collisions avec les variables internes à  Apple, genre préférer "m_toto" (pour reprendre une notation couramment utilisée en C++, "m" voulant dire "member", variable membre, autre nom donné aux variables d'instance en C++). Ceci dit si tu codes avec le modern runtime (ce qui est toujours le cas sous iOS, et le cas pour OSX en 64 bits) tu n'as plus besoin de prévoir une ivar pour gérer le stockage des valeurs de tes @property, donc tu n'as même plus à  déclarer d'ivar tu peux déclarer uniquement ta "@property toto", et comme ça tu n'as plus à  te poser de question.
  • 22:01 modifié #15
    //fichier.h
    @interface FluxRSSParser : NSObject <NSXMLParserDelegate>{
    NSMutableString * _currentItemValue;
    }
    @property(nonatomic, retain) NSMutableString * currentItemValue;

    @end

    //fichier.m

    @synthesize currentItemValue = _currentItemValue;




    Donc on déclare une variable d'instance _currentItemValue
    puis une propriété currentItemValue

    Si j'ai bien compris ces 2 choses sont indépendantes.
    et dans le synthetise on met un egale.

    Cela signifie donc que l'on affecte la propriété a la variable d'instance ?

    C'est vraiment pertubant parce que si je declare
    la variable d'instance *mavar
    et la proprieté *mavar
    ... avec le meme nom,
    je declare en fait 2 choses différentes, et dans le synthetise le fait de faire
    @synthetise mavar;

    va synthetise les 2 éléments d'un coup comme si je faisais vulgairement
    @synthetise mavar; (la ivar)
    @synthetise mavar; (la proprieté)

    Est-ce que je me trompe ?
  • AliGatorAliGator Membre, Modérateur
    22:01 modifié #16
    Non cela ne va pas synthétiser 2 éléments d'un coup
    Une variable d'instance et une propriété sont deux choses différentes, bien que proches. Une propriété utilise une variable d'instance pour stocker la valeur de la propriété.

    Après :
    - Soit tu mets un nom différent pour ta propriété et ta variable d'instance (ce que je te conseille pour t'aider à  faire la distinction entre les deux, parce que sinon l'amalgame est vite arrivé surtout si tu débutes tu vas risquer de les confondre), et dans ce cas si tu veux automatiquement synthétiser les accesseurs à  ta propriété, tu écris dans le .m [tt]@synthesize maPropriete = laVariableDInstanceAssociee[/tt]...
    - Soit tu lui donnes le même nom, et tu pourrais alors écrire la même chose (sauf que le nom de ta propriété et de ta variable d'instance étant identiques, cela donnerait un truc comme [tt]@synthesize leNom = leNom[/tt])... ou encore du coup tu utilises la syntaxe raccourcie [tt]@synthesize leNom[/tt] qui est strictement équivalente à  écrire [tt]@synthesize leNom = leNom[/tt] et est pratique si le nom de ta propriété (que tu mets à  gauche du signe égal de la syntaxe de @synthesize) est le même que le nom de la ivar qui lui sert de stockage (et que tu mets à  droite du signe égal).

    Donc si tu déclares la pripriété et la variable d'instance avec le même nom, écrire @synthesize mavar va synthétiser la propriété (ça veut rien dire de faire @synthesize unevariable en fait, on ne synthétise que des propriétés, @synthesize écrit les méthodes de getter/setter associées à  une propriété), mais en utilisant la variable d'instance du même nom que la propriété comme variable de stockage, puisque tu n'as pas précisé avec un "= xxx" qu'il fallait lui associer une propriété au nom différent.

    Encore une fois je te conseille :
    - Soit d'utiliser des noms différents pour la propriété et la variable d'instance, ça t'évitera de confondre les deux notions et surtout t'évitera de risquer d'affecter la variable d'instance directement là  où tu devrais utiliser la propriété pour que la gestion de la mémoire se fasse efficacement
    - Soit de ne pas du tout déclarer la variable d'instance à  associer à  la propriété, et laisser le compilateur générer cette variable d'instance à  la volée pour toi, ce qui rend le fichier .h plus clair en plus... (mais n'est possible qu'avec le Modern Runtime, donc si tu codes pour iOS cela ne pose aucun problème car iOS a toujours utilisé le Modern Runtime, si tu codes une appli pour OSX ça n'est vrai que si tu compiles en 64 bits)
  • 22:01 modifié #17
    ok donc on synthétise des proprietés !


    Sinon par exemple hidden qui est une proprieté.

    quand je fais un pomme click dessus, j'arrive dans la classe ou elle est definie, par contre je ne trouve pas la méthode qui fait que hidden rende une élément image, label ou autre caché.

    Est ce que ca se trouve dans le code d'apple ou est ce que c'est caché?
  • AliGatorAliGator Membre, Modérateur
    juin 2011 modifié #18
    Quand on déclare une "@property NSString* toto" cela :
    - revient à  déclarer un setter "-(void)setToto:(NSString*)value" et un getter "-(NSString*)value". A moins que tu modifies les noms des setter et getter par défaut, ou que tu ne mettes readonly, etc.
    - indique également une Memory Managment Policy (assign, retain ou copy), ainsi qu'une threading policy (nonatomic ou atomic)

    Après, si tu utilises dans ton .m "@synthesize";, le compilateur va te générer automatiquement le code par défaut pour ces méthodes setter ([tt]-(void)setToto:(NSString*)value[/tt]) et getter ([tt]-(NSString*)toto[/tt]), en prenant en compte les politiques de mémoire et de threading définies par les attributs de la propriété lors de sa déclaration, les appels nécessaires pour le KVO, etc.
    Mais tu peux aussi écrire ces méthodes de setter et getter toi-même plutôt que de laisser @synthesize les générer lui-même (mais dans ces cas là  il faut que tu saches ce que tu fais et comment implémenter un setter et un getter sans tomber dans les pièges, cf la doc tout est expliqué)
  • 22:01 modifié #19
    Tu ne verras que les headers, pas le code.
    si tu vois une @property hidden, en readwrite, c'est que dans le .m Apple a implémenté:
    <br />- (void)setHidden:(BOOL)hiddenValue<br />{<br />	@synchronized(self){<br />		if(hidden!=hiddenValue)<br />		{<br />			[self willChangeValueForKey:@&quot;hidden&quot;];<br />			hidden = hiddenValue;<br />			..... // code permettant de masquer la vue.<br />			[self didChangeValueForKey:@&quot;hidden&quot;];<br />		}<br />	}<br />}<br />
    
  • AliGatorAliGator Membre, Modérateur
    22:01 modifié #20
    Sujet déplacé dans la section commune iOS/OSX
Connectez-vous ou Inscrivez-vous pour répondre.