pseudo variable "de classe"

ChachaChacha Membre
08:52 modifié dans API AppKit #1
Bonjour,

Bien que j'aie trouvé des documents en parlant, il est actuellement impossible d'utiliser des variables de classe en Objective-C avec gcc.
Ce n'est pas très grave, il suffit de déclarer une variable globale dans le fichier .m de la classe et de faire "comme si".
Cependant, je me demande quelle est la bonne manière d'initialiser/détruire une telle variable:
-pour l'initialiser, je le fais dans le +(void) initialize de la classe
-en revanche, je me pose la question de la libération de la mémoire associée à  la variable. Bien sûr, quand on va quitter le programme, le système d'exploitation va libérer cette mémoire, mais je n'ai pas envie de déléguer cette tâche à  quelque chose d'extérieur à  mon programme.
Il n'y a pas de  méthode +(void) deinitialize.

Des idées ? Comment faites-vous ?

+
Chacha

Réponses

  • BruBru Membre
    08:52 modifié #2
    Ah bon ? Impossible ?

    Car, déclarer les variables dans le .m hors de l'implémentation fait que ce sont des variables de classe (au sens Objective-C du terme) !

    Par contre, on ne peut pas décharger une classe (elle reste en mémoire pendant toute le vie de la "zone").

    Enfin, initialize peut, dans certaines conditions, être appelé plusieurs fois par le runtime pour la même classe, il faut donc être vigilent sur cet aspect là .

    .

  • ChachaChacha Membre
    mars 2005 modifié #3
    dans 1109769587:

    Ah bon ? Impossible ?

    Je veux dire comme syntaxe propre au langage. Voici la faq d'où je tire mon affirmation:
    http://www.faqs.org/faqs/computer-lang/Objective-C/faq/

    15.1 What's the syntax for class variables ?
       List the class variables after the instance variables, and group them
       together in the same way as instance variables, as follows :
       
    @implementation MyClass : Object { id ivar1; int ivar2; } : { id cvar1; }
    @end

    Et bien pour le moment, ça ne compile pas avec gcc...


    Par contre, on ne peut pas décharger une classe (elle reste en mémoire pendant toute le vie de la "zone").

    Donc je n'ai pas à  désallouer mes variables... il va falloir que je me fasse à  cette idée !


    Enfin, initialize peut, dans certaines conditions, être appelé plusieurs fois par le runtime pour la même classe, il faut donc être vigilent sur cet aspect là .


    Ah bon ? Donc il me faut mettre une garde supplémentaire
    <br />+(void) initialize<br />{<br />  if (!MaVariableDeClasse)<br />    MaVariableDeClasse = [[NSTruc alloc] init];<br />}<br />
    

    Dans quels cas peut-ce être appelé plusieurs fois ?

    +
    Chacha
  • BruBru Membre
    08:52 modifié #4
    dans 1109770284:


    Enfin, initialize peut, dans certaines conditions, être appelé plusieurs fois par le runtime pour la même classe, il faut donc être vigilent sur cet aspect là .


    Ah bon ? Donc il me faut mettre une garde supplémentaire
    <br />+(void) initialize<br />{<br />&nbsp; if (!MaVariableDeClasse)<br />&nbsp; &nbsp; MaVariable = [[NSTruc alloc] init];<br />}<br />
    

    Dans quels cas peut-ce être appelé plusieurs fois ?


    Le cas par exemple où initialize peut être appelé plusieurs fois s'applique pour les sous-classes.

    Imaginons 3 classes, A, B et C. C hérite de B qui hérite de A.

    Lorsque le runtime va charger les classes, il va s'assurer que le message initialize est transmis aux classes du parent le plus éloigné vers l'enfant le plus proche. Donc dans notre cas, ce message va chronologiquement être envoyé d'abord à  A, puis à  B et enfin à  C.

    Le problème est que si B n'implémente pas la méthode de classe initialize, automatiquement, le message va au parent soit A. Donc le message sera transmis à  A, puis à  A (par héritage de B) et enfin à  C.

    D'où 2 appels à  initialize de A.

    .
  • ClicCoolClicCool Membre
    mars 2005 modifié #5
    en effet Bru si tu sais dans quels cas un initialize peut)être envoyé 2 fois à  une classe, ça nous interresse.

    Apple manquant de précision sur ce coup là :
    Normally the runtime system sends a class just one initialize message. However, if for some reason an application or the runtime system generates additional initialize messages, it is a good idea to prevent code from being invoked more than once


    surtout que quelques lignes plus haut on pouvait lire:
    Each class receives the initialize message just once from the runtime system


    .... et après on s'etend dire RTFM  >:)

    [GRILLED] merci Bru
  • ChachaChacha Membre
    08:52 modifié #6
    dans 1109773123:

    Le cas par exemple où initialize peut être appelé plusieurs fois s'applique pour les sous-classes.

    Imaginons 3 classes, A, B et C. C hérite de B qui hérite de A.

    Lorsque le runtime va charger les classes, il va s'assurer que le message initialize est transmis aux classes du parent le plus éloigné vers l'enfant le plus proche. Donc dans notre cas, ce message va chronologiquement être envoyé d'abord à  A, puis à  B et enfin à  C.

    Le problème est que si B n'implémente pas la méthode de classe initialize, automatiquement, le message va au parent soit A. Donc le message sera transmis à  A, puis à  A (par héritage de B) et enfin à  C.

    D'où 2 appels à  initialize de A.


    Je viens de vérifier, c'est parfaitement exact ; mais c'est une sacrée chausse-trape ! Il y a de quoi créer de beaux bugs si l'on en n'est pas conscient.

    Merci, Bru

    +
    Chacha
  • BruBru Membre
    mars 2005 modifié #7
    dans 1109770284:

    dans 1109769587:

    Ah bon ? Impossible ?

    Je veux dire comme syntaxe propre au langage. Voici la faq d'où je tire mon affirmation:
    http://www.faqs.org/faqs/computer-lang/Objective-C/faq/

    15.1 What's the syntax for class variables ?
      List the class variables after the instance variables, and group them
      together in the same way as instance variables, as follows :
     
    @implementation MyClass : Object { id ivar1; int ivar2; } : { id cvar1; }
    @end

    Et bien pour le moment, ça ne compile pas avec gcc...


    Dans la documentation Objective C d'Apple, la seule méthode évoquée pour créer des variables de classe est bien la déclaration et l'utilisation de variables "static" :

    Documentation Apple

    Variables and Class Objects

    When you define a new class of objects, you can specify instance variables for them. Every instance of the class will have its own copy of all the variables you declare; each object controls its own data.

    However, you can't prescribe variables for the class object; there are no “class variable” counterparts to instance variables. Only internal data structures, initialized from the class definition, are provided for the class. The class object also has no access to the instance variables of any instances; it can't initialize, read, or alter them.

    Therefore, for all the instances of a class to share data, an external variable of some sort is required. Some classes declare static variables and provide class methods to manage them. (Declaring a variable static in the same file as the class definition limits its scope to just the class"and to just the part of the class that's implemented in the file. Unlike instance variables, static variables can't be inherited by subclasses.)

    Static variables help give the class object more functionality than just that of a “factory” producing instances; it can approach being a complete and versatile object in its own right. A class object can be used to coordinate the instances it creates, dispense instances from lists of objects already created, or manage other processes essential to the application. In the case when you need only one object of a particular class, you can put all the object's state into static variables and use only class methods. This saves the step of allocating and initializing an instance.

    Note: It is also possible to use external variables that weren't declared static, but the limited scope of static variables better serves the purpose of encapsulating data into separate objects.


    .
  • FloFlo Membre
    08:52 modifié #8
    Bonjour à  tous !

    Je me permets de faire remonter cet intéressant post afin de savoir si l'objective-c 2.0 avait changé la donne, à  savoir, y-a-t-il un moyen "propre", intégré au langage pour déclarer et manager des variables de classes ?

    J'ai essayé les solutions du post en déclarant mes variables de classes dans le fichier .h (avec le mot clé static) en mettant des méthodes de classe pour y accéder/modifier mais j'ai des warnings qui me disent que mes variables ne sont pas utilisées. Ca m'embête un peut de les déclarer dans le .m...

    Merci d'avance pour vos réponses !
  • NoNo Membre
    février 2009 modifié #9
    dans 1234628359:

    Je me permets de faire remonter cet intéressant post afin de savoir si l'objective-c 2.0 avait changé la donne, à  savoir, y-a-t-il un moyen "propre", intégré au langage pour déclarer et manager des variables de classes ?
    J'ai essayé les solutions du post en déclarant mes variables de classes dans le fichier .h (avec le mot clé static) en mettant des méthodes de classe pour y accéder/modifier mais j'ai des warnings qui me disent que mes variables ne sont pas utilisées. Ca m'embête un peut de les déclarer dans le .m...


    Non pas à  ma connaissance.
    donc static est toujours le passage obligé dans le... .m !

    Et surtout pas le .h, car chaque #import (ou include) du .h dans d'autres fichiers sources va créer ces variables inutilement.

    De manière presque élégante, rien ne t'empêche de les déclarer à  part dans le .m bien séparer du reste du code.
    Pour m part, je fais ceci :
    <br />#import &quot;MaClasse.h&quot;<br /><br />// variables de classe de MaClasse<br /><br />static id __unObjet=nil;<br />static int __unNombre=0;<br />static BOOL __dejaInitialise=NO;<br /><br />// implementation de la classe MaClasse<br /><br />@implementation MaClasse<br /><br />+ (void)initialize<br />{<br />   if (! __dejaInitialise)<br />   {<br />      __unNombre=1;<br />      __unObjet=[[NSObject alloc] init];<br />      __dejaInitialise=YES;<br />   }<br />}<br /><br />// reste de l&#39;implementation de la classe...<br /><br />@end <br />
    

  • FloFlo Membre
    08:52 modifié #10

    Et surtout pas le .h, car chaque #import (ou include) du .h dans d'autres fichiers sources va créer ces variables inutilement.


    Oui j'avais pas pensé à  ça... de toute façon le compilo plante dès qu'on se met à  faire des méthodes accédant à  des variables "static"(déclarées dans le .h).

    Sinon dans ton code je vois ça :

    static BOOL __dejaInitialise=NO;


    Après une petite recherche sur la doc Apple j'ai lu ceci :


    If a particular class does not implement initialize, the initialize method of its superclass is invoked twice, once for the superclass and once for the non-implementing subclass. If you want to make sure that your class performs class-specific initializations only once, implement initialize as in the following example:


    <br />@implementation MyClass<br />+ (void)initialize<br />{<br />&nbsp; &nbsp; if ( self == [MyClass class] ) {<br />&nbsp; &nbsp; &nbsp; &nbsp; /* put initialization code here */<br />&nbsp; &nbsp; }<br />}<br />
    


    Donc ma question est la suivante, quelle est l'intérêt de ce booléen par rapport au code fourni par Apple ?

    En tous cas merci pour ta réponse !
  • MalaMala Membre, Modérateur
    février 2009 modifié #11
    On peut donner une valeur par défaut à  un type (int, char, bool, etc) mais on ne peut pas créer un objet par défaut pour les classes. On mets donc le pointeur à  nil et lors de l'initialisation on peut créer l'objet.
  • mpergandmpergand Membre
    08:52 modifié #12
    exemple:
    <br />// macro définie par ailleurs<br /><br />#define COCOA_INITIALIZE_ONCE			&#092;<br />			static BOOL _init_=FALSE;	&#092;<br />			if(_init_) return;			&#092;<br />			_init_=TRUE;<br /><br />/*	----	exemple		-----	*/<br /><br />static NSColor* color;<br /><br /><br />@implementation MaClasse<br /><br />+(void) initialize<br />{<br />	COCOA_INITIALIZE_ONCE<br />	<br />	color=[[NSColor colorWithCalibratedRed:.7 green:.89 blue:.52 alpha:1.0]retain];<br />}<br /><br />+(NSColor*) color<br />{<br />	return color;<br />}
    

  • FloFlo Membre
    08:52 modifié #13
    Heu... excusez-moi je me suis mal exprimé :

    Je sais que le booléen est là  pour éviter d'initialiser plusieurs fois les variables de classe si des sous-classes n'implémentant pas la méthode initialize: font appel à  l'initialize: de la super classe.

    Le truc que je me demande, c'est pourquoi utiliser un booléen qui se rappelle si on est déjà  passé dans initialize alors qu'Apple nous proposer de faire le test :
    <br />if ( self == [MyClass class] )<br />
    

  • NoNo Membre
    08:52 modifié #14
    dans 1234636302:

    Heu... excusez-moi je me suis mal exprimé :

    Je sais que le booléen est là  pour éviter d'initialiser plusieurs fois les variables de classe si des sous-classes n'implémentant pas la méthode initialize: font appel à  l'initialize: de la super classe.

    Le truc que je me demande, c'est pourquoi utiliser un booléen qui se rappelle si on est déjà  passé dans initialize alors qu'Apple nous proposer de faire le test :
    <br />if ( self == [MyClass class] )<br />
    




    C'est une autre façon de faire... celle de Apple, mais qui n'est qu'une parmi d'autre afin d"éviter d'exécuter le code initialize plusieurs fois.

    C'est comme faire la sommation donnant comme résultat le chiffre 4 :
    - moi, je dirais 3+1,
    - Apple, dirait sans doute 1+1+1+1,
    - Mala choisirait sans doute 2+2,
    - alors que Mpergand écrirait 1+3...
  • FloFlo Membre
    08:52 modifié #15
    Ok merci, je pensais qu'il y avait une raison particulière...

    Si toutes les solutions ont le même effet, je vais faire plaisir à  Apple en choisissant la leur ! :o
Connectez-vous ou Inscrivez-vous pour répondre.