Propriétés sans iVars ?

NeofelisNeofelis Membre
mai 2011 modifié dans Objective-C, Swift, C, C++ #1
Bonjour,

Je suis tombé sur ce lien avec un post très intéressant d'Ali http://pommedev.mediabox.fr/frameworks-communs-objective-c/(tutocours)-variables-d'instance-proprietes-et-accesseurs/

J'ai bien compris qu'une propriété n'était pas forcément lié à  une variable d'instance si les accesseurs ne sont pas créés automatiquement.

Mais je viens de faire un test surprenant : J'ai créé une propriété basique (contenant un BOOL ou un NSString par exemple) et j'ai généré automatiquement mes accesseurs avec @synthesize. En supprimant la déclaration de ma variable d'instance j'ai constaté que tout fonctionnait parfaitement. Mon getter et setter continuait de récupérer et stocker mes valeurs. Comment est-ce possible ? Où est stockée la valeur dans mon setter si aucune variable d'instance n'est déclarée et que je ne fournis à  mes accesseurs aucun mécanisme de stockage ?  J'en viens à  me demander si déclarer une iVar est utile lorsque l'on déclare une propriété ???

Réponses

  • BunoBuno Membre
    19:41 modifié #2
    C'est de la tambouille interne.  :P
  • muqaddarmuqaddar Administrateur
    19:41 modifié #3
    dans 1306510365:

    C'est de la tambouille interne.  :P


    Oui.
    En tout cas, ça fait du bien d'avoir quelques nouveaux qui aiment comprendre la tambouille. Et ça mérite d'être souligné. 
  • Eddy58Eddy58 Membre
    19:41 modifié #4
    dans 1306508103:

    En supprimant la déclaration de ma variable d'instance j'ai constaté que tout fonctionnait parfaitement. Mon getter et setter continuait de récupérer et stocker mes valeurs. Comment est-ce possible ? Où est stockée la valeur dans mon setter si aucune variable d'instance n'est déclarée et que je ne fournis à  mes accesseurs aucun mécanisme de stockage ?  J'en viens à  me demander si déclarer une iVar est utile lorsque l'on déclare une propriété ???


    Tu compiles en 32 ou 64 bits ? Mets-toi en 32 bits only et normalement tu auras un message d'erreur.
  • BunoBuno Membre
    19:41 modifié #5
    dans 1306510830:

    Oui.
    En tout cas, ça fait du bien d'avoir quelques nouveaux qui aiment comprendre la tambouille. Et ça mérite d'être souligné. 

    Tout à  fait d'accord même si, moi-même, je n'ai pas creusé la question  :o
  • NeofelisNeofelis Membre
    19:41 modifié #6
    dans 1306510993:

    dans 1306508103:

    En supprimant la déclaration de ma variable d'instance j'ai constaté que tout fonctionnait parfaitement. Mon getter et setter continuait de récupérer et stocker mes valeurs. Comment est-ce possible ? Où est stockée la valeur dans mon setter si aucune variable d'instance n'est déclarée et que je ne fournis à  mes accesseurs aucun mécanisme de stockage ?  J'en viens à  me demander si déclarer une iVar est utile lorsque l'on déclare une propriété ???


    Tu compiles en 32 ou 64 bits ? Mets-toi en 32 bits only et normalement tu auras un message d'erreur.


    Effectivement ! Est-ce un bug ? Y'a-t-il un moyen d'avoir toutes les erreurs attendues en 64 bits ? ^^
  • Eddy58Eddy58 Membre
    19:41 modifié #7
    Non ne t'inquiètes pas ce n'est pas un bug, c'est juste une convention pour dire que tu veux de l'ObjC 64 bits. Normalement ça ne se déclare pas tout à  fait comme ça, mais ne voyant pas de déclarations de variables, la "tambouille interne" en fait abstraction et passe direct en mode 64 bits.

    Interfaçage en 32 bits :

    @interface MaClasse : NSObject
    {
    NSString *propriete1;
    NSArray *propriete2;
    }

    @property (nonatomic,retain) NSString *propriete1;
    @property (nonatomic,retain) NSArray *propriete2;

    -(void)methode;

    @end


    Interfaçage en 64 bits :

    @interface MaClasse : NSObject

    @property (nonatomic,retain) NSString *propriete1;
    @property (nonatomic,retain) NSArray *propriete2;


    -(void)methode;

    @end
  • zoczoc Membre
    19:41 modifié #8
    dans 1306512596:

    Effectivement ! Est-ce un bug ?

    Non, c'est une fonctionnaité du "modern runtime", disponible pour les applications Mac 64 bits et les applications iOS à  partir de la version 4.


    Tous les détails sont dans la documentation officielle concernant le runtime objective-c ;)
  • AliGatorAliGator Membre, Modérateur
    mai 2011 modifié #9
    En fait ca n'est pas directement lié avec le fait qu'on soit 32 ou le 64 bits, mais lié au runtime Objective-C utilisé.

    En effet, il existe deux Runtimes : le "Legacy Runtime" (traduisez "Runtime Historique") qui nécessite de déclarer les ivar, et le "Modern Runtime" (traduisez... bah devinez ^^) qui permet de se passer de la déclaration de la ivar, le @synthesize sachant la générer automatiquement.

    Après, c'est vrai qu'il se trouve que sous MacOSX 32 bits, c'est le Legacy Runtime qui est encore utilisé, et sous MacOSX 64 bits, c'est le Modern Runtime qui est utilisé. Et sous iOS ça a toujours été le Modern Runtime.

    Tout est expliqué ici dans la doc (et tu as aussi un lien, dans ce paragraphe, vers l'article Runtime Versions and Platforms qui indique quels runtimes sont utilisés suivant la plateforme)
  • muqaddarmuqaddar Administrateur
    mai 2011 modifié #10
    dans 1306514356:

    dans 1306512596:

    Effectivement ! Est-ce un bug ?

    et les applications iOS à  partir de la version 4.


    Tu as devancé ma question pour iOS. ;)
    Vu le nombre de classes modèles que j'ai multiplié par le nombre de iVars, ça donne envie de s'y mettre...

    Bon, ça veut dire que je coupe le pont avec iOS 3.2... mais pourquoi pas ?

    EDIT:
    Ali a répondu à  ma question... adieu les déclarations d'iVar sur iOS alors... ;)
  • AliGatorAliGator Membre, Modérateur
    19:41 modifié #11
    D'après la doc toutes les applications iOS utilisent le Modern Runtime, et pas que depuis iOS4...
    Coquille dans la doc ou réalité ?

    En tout cas moi j'omet de plus en plus les ivars, surtout quand je veux faire une interface de classe (.h) plus propre et lisible en n'exposant que les @property. Par exemple pour ma classe OHAttributedLabel sur github j'ai supprimé toutes les backing variables de mon .h.
  • NeofelisNeofelis Membre
    mai 2011 modifié #12
    Nickel ! Merci à  tous. :)

    C'est vrai que j'ai encore un peu de mal avec la doc, elle est tellement complète (et c'est une qualité) que je ne sais parfois pas où chercher alors que mes réponses se trouvent dans 99% des cas dedans ^^
  • muqaddarmuqaddar Administrateur
    19:41 modifié #13
    dans 1306514749:

    D'après la doc toutes les applications iOS utilisent le Modern Runtime, et pas que depuis iOS4...
    Coquille dans la doc ou réalité ?


    Je viens de faire un test sans soucis en compilant pour iOS 3.2. ;)
  • FloFlo Membre
    19:41 modifié #14

    En tout cas moi j'omet de plus en plus les ivars, surtout quand je veux faire une interface de classe (.h) plus propre et lisible en n'exposant que les @property. Par exemple pour ma classe OHAttributedLabel sur github j'ai supprimé toutes les backing variables de mon .h.


    J'avais remarqué ça en bidouillant, il y a néanmoins un gros problème lié à  cette pratique, le débuggueur n'affiche que les ivars déclarées dans le .h. Donc si tu veux inspecter tes ivars en mode debug ça semble râpé... A moins qu'il y ait une astuce pour inspecter les ivars dans le débuggueur même si elles ne sont pas déclarées dans le .h ?  :o
  • laudemalaudema Membre
    19:41 modifié #15
    Si tu mets un point d'arrêt sur la ligne de @synthesize il s'arrêtera à  chaque fois que le setter ou le getter sera appelé. En fait il le fait pour le 32 bits avec une variable, en 64 je ne sais pas et ne suis pas en configuration pour le tester.
    Sil le fait par contre je ne sais pas quelle variable tu pourrais lire, peut être y en aura t'il une du même nom que la @property correspondante ?
  • AliGatorAliGator Membre, Modérateur
    19:41 modifié #16
    En fait je regarde rarement les valeurs de mes variables dans le débogueur. Au début du projet peut-être, de temps en temps, mais sinon, je tape les commandes de gdb directement dans la fenêtre de commande de gdb. Genre "[tt]po mavariable[/tt]" pour regarder la valeur de mavariable. Ou encore je met des breakpoints sonores (qui jouent un son au lieu d'interrompre le programme... ou qui prononcent du texte, texte dans lequel je peux mettre la valeur de ma variable) ou sinon des NSLogs...

    Bref c'est loin d'être gênant pour moi de ne pas voir dans le débogueur les backing variables associées à  mes @properties. Après tout, si je ne les crée pas moi-même, c'est pour ne pas m'en soucier, et ne voir cela comme des propriétés (gérées de façon autonomes) et pas des accesseurs à  une ivar donnée (que j'aurais définie)
  • laudemalaudema Membre
    19:41 modifié #17
    Dans l'éditeur de point d'arrêt tu peux mettre une commande de gdb [tt]po [self maProperty] [/tt]par exemple fonctionnera très bien si mProperty répond à  [tt]description[/tt]. Tu peux même mettre une condition nécessaire au déclenchement du point d'arrêt et ça ne s'affichera dans la console que si la condition est remplie, ça peut aussi bien être un booléen dans ton code... J'ai découvert ça il y a peu avec beaucoup de soulagement :)
  • AliGatorAliGator Membre, Modérateur
    19:41 modifié #18
    Bah oui c'est ce que je viens de dire plus haut, c'est comme ça que je fais moi :P
  • laudemalaudema Membre
    19:41 modifié #19
    dans 1307301101:

    Bah oui c'est ce que je viens de dire plus haut, c'est comme ça que je fais moi :P

    ça ne m'étonne pas de toi :D
    J'ai oublié de préciser qu'il fallait aussi cocher la petite case à  droite, la colonne avec la flèche => pour avoir le plaisir de suivre l'évolution du code dans la console sans que l'appli s'arrête à  la ligne indiquée..
  • FloFlo Membre
    19:41 modifié #20
    Ok, mais dommage que le debugeur ne soit pas capable de se débrouiller tout seul pour afficher les ivars et qu'on soit obligé de bidouiller  :(
  • AliGatorAliGator Membre, Modérateur
    19:41 modifié #21
    dans 1307439268:

    Ok, mais dommage que le debugeur ne soit pas capable de se débrouiller tout seul pour afficher les ivars et qu'on soit obligé de bidouiller  :(
    ??
    Mais le débugeur sait tout à  fait se débrouiller tout seul pour afficher les ivars, pourquoi tu dis ça ?

    On parle de propriétés opaques sans backing variables dans ce thread justement, donc ce ne sont pas des variables, mais bien des propriétés. Et comme une propriété peut être transciente et voir sa valeur calculée (voir les messages que j'ai fait sur le forum sur les @properties) et non pas juste issue d'une variable d'instance, encore heureux que le compilateur ne cherche pas à  afficher sa valeur à  chaque fois dans le débogueur si on lui demande pas !
  • FloFlo Membre
    19:41 modifié #22

    Mais le débugeur sait tout à  fait se débrouiller tout seul pour afficher les ivars, pourquoi tu dis ça ?


    Autant pour moi, je crois que je me suis un peu emmêlé le vocabulaire  :D

    En gros ce que je veux dire c'est : si j'ai la classe MaClasse suivante :

    <br />@interface MaClasse : NSObject {}<br /><br />@property(nonatomic, retain) NSString *maVariable; // avec @synthesize dans le .m<br /><br />- (void) maMethode;<br /><br />@end<br />
    


    Quand je vais vouloir par exemple faire du pas à  pas en mode debug sur maMethode, dans le petit triangle >self , il n'y aura pas maVariable. Par contre, si j'avais déclarée maVariable elle aurait été disponible directement dans le debugger :

    <br />@interface MaClasse : NSObject <br />{<br />&nbsp; &nbsp;  NSString *maVariable;<br />}<br /><br />@property(nonatomic, retain) NSString *maVariable; // avec @synthesize dans le .m<br /><br />- (void) maMethode;<br /><br />@end<br />
    


    Dans la première situation il va falloir utiliser les commandes du debugger, mais pas dans la deuxième...
  • AliGatorAliGator Membre, Modérateur
    juin 2011 modifié #23
    Oui mais dans la 2e solution, c'est la backing variable, donc la variable maVariable, que tu vois, pas la propriété.

    Autre exemple, en prenant des noms différents et plus explicites pour bien saisir le vocabulaire :
    @interface MaClasse : NSObject<br />{<br />&nbsp; NSString* maVar1;<br />}<br />@property NSString* maProp1;<br />@property NSString* maProp2;<br />@property(readonly) NSString* maProp3;<br />@end<br /><br />@implementation MaClasse<br />@synthesize maProp1 = maVar1; // associé à  une backing variable explicitement<br />@synthesize maProp2; // laisser le modern runtime gérer le backing store (la variable qui va stocker la valeur) de la propriété<br />-(NSString*)maProp3 {<br />&nbsp; // Propriété &quot;calculée&quot; d&#039;après d&#039;autres valeurs<br />&nbsp; return [NSString stringWithFormat:@&quot;Toto %@ Tata&quot; , maVar1];<br />}<br />@end
    


    Ici dans le débogueur tu ne verras que maVar1. Tu ne verras pas maProp2 ni maProp3... ni maProp1 en fait (tu verras maVar1 et il se trouve que maProp1 se base sur cette variable d'instance pour stocker sa valeur, mais bon ça reste la variable que tu vois, pas la propriété).

    Et autant on peut comprendre qu'on aimerait pouvoir voir maProp1 et maProp2 dans le débogueur... mais si tu regardes le cas de maProp3 tu comprends que pour ce cas ce n'est pas trop possible simplement : faudrait que le débogueur exécute le code du getter pour afficher la variable, et ça tu n'as peut-être pas envie qu'il le fasse si tu ne le demandes pas explicitement.
    Genre dans mon exemple ça va encore, mais si j'avais à  la place fait une requête réseau pour demander la valeur à  un WebService avant de la retourner... hum !

    Bon après ok à  la limite s'il détectais que le code de la @property avait été compilée/générée automatiquement via un @synthesize et pas manuellement via du code "perso", et seulement dans ce cas affichait la valeur de ladite @property à  côté de la liste des variables, ça pourrait être sympa.
    Mais faut garder à  l'esprit que ça reste des "propriétés" et pas des "variables".

    Certes on confond parfois les deux car on a pris l'habitude qu'il y ait une variable d'instance d'associée à  nos @property, justement avec le Modern Runtime ce n'est plus vrai (ou bien c'est vrai mais cette ivar est créée à  la volée par le compilateur -- Dieu sait quel nom le compilo lui donne d'ailleurs à  cette variable en interne -- et est masquée du code). Or on n'a toujours vu que les variables dans cette fenêtre en haut du compilateur, jamais les propriétés.
  • FloFlo Membre
    19:41 modifié #24
    Ok merci, c'est plus clair maintenant 
Connectez-vous ou Inscrivez-vous pour répondre.