Initialiser une variable de classe
Flo
Membre
Bonjours à tous !
Je patauge un petit peu avec mes variables de classes :
Mes variables de classe sont déclarées en static et j'ai des messages d'erreur à l'execution du type :
Quelqu'un aurait-il une explication ?
Je patauge un petit peu avec mes variables de classes :
<br />+ (void) initialize<br />{<br /> NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];<br /> <br /> if ( self == [ITDataGraph class] ) <br /> {<br /> undoManager = [[NSUndoManager alloc] init];<br /> <br /> NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);<br /> NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex: 0] : NSTemporaryDirectory();<br /> <br /> dataFolder = [basePath stringByAppendingPathComponent: DATA_FOLDER];<br /> dataFile = [dataFolder stringByAppendingPathComponent: DATA_FILE];<br /> }<br /> <br /> [pool drain];<br />}<br />
Mes variables de classe sont déclarées en static et j'ai des messages d'erreur à l'execution du type :
2009-02-19 11:12:53.004 iTrend[597:10b] *** _NSAutoreleaseNoPool(): Object 0x10a340 of class ITDataGraph autoreleased with no pool in place - just leaking
Stack: (0x9342e73f 0x9333ae32 0x25c2 0x285e 0x9515abdf 0x951540d3 0x8fe02e38 0x8fe0e7cf 0x8fe0e8c9 0x8fe04102 0x8fe07bcf 0x8fe01872 0x8fe01037)
Quelqu'un aurait-il une explication ?
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Pourquoi avoir plein de variables statiques comme ça ? C'est super crade
Par ce procédé, j'entends partager ces variables avec chaque instance de la classe comme des vrais variables de classe quoi ! Ne serait-ce pas possible en objective-c ?
(au pire des singletons...)
Des propos d'Apple, on peut même mettre toutes les variables d'une classe en variable de classe si cette dernière ne doit être instanciée qu'une fois, alors je vois pas trop en quoi ce que je suis en train de faire est si monstrueux...
http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/chapter_3_section_10.html
Parce que c'est pas du tout MVC et pas du tout Thread safe (et pas du tout esprit Cocoa).
Où est-ce qu'Apple parle de ça ?
Mais bon vu la levée de bouclier je crois que je vais me raviser...
Sinon, je reste persuadé que le message de "leak" n'a rien à voir avec ce code précis.
Où est le code ou tu appelles un "autorelease" sur un objet ITDataGraph ? (parce que c'est pas le cas dans ce code !)
Le problème c'est qu'un autorelease est envoyé à ITDataGraph alors que pour l'instant je n'instantie pas du tout cette classe. J'ai des héritier mais aucune déclaration explicite de variable de type ITDataGraph...
Si c'est une méthode de classe de ITDataGraph, c'est évident que "self==[ITDataGraph class]", non ? ???
Je crois que c'est un truc à cause des méthodes virtuelles, genre si tu as une classe B qui dérive de ta classe A et que tu appelles [super initialize] dedans ou que le initialize n'est pas défini... ça va appeler celui de la classe parent, donc A, et du coup le initialize de A va être appelé une fois pour A une fois pour B...
D'où le test.
[EDIT] J'ai retrouvé le post où Bru explique ça, c'est ici
http://www.objective-cocoa.org/forum/index.php?topic=694.msg32557#msg32557
[pool release] ?
sinon à quoi sert le pool ici ? c'est du multi-threads ?
Effectivement, j'ai pensé à ce cas en voyant le test... mais ça n'est valable que pour les classes qu'on souhaite sous-classer que je sache, non ? ???
Edit : je me suis posé la même question pour l'auto-release pool...
Yes, en fait la classe ITDataGraph me sert à partager un certain nombre de variable à tous les noeuds du graph qui sont aussi de type ITDataGraph. J'ai un certain nombre de classe qui héritent de ITDataGraph et qui sont par conséquent des noeuds du graph.
En fait j'aurais du poster le lien du post de Bru dès le début, post que j'ai fait remonté ya pas longtemps dailleur...
Pour l'autoreleasePool c'est une bête supposition de ma part, j'ai vu un message d'erreur du style NoAutoreleasePool et je me suis dit "tiens il faut que j'en créer une ?".
En fait le problème est tout autre, j'ai eu la bêtise de nommer une des methodes de la classe ITDataGraph : + (void) load... Ne sachant pas à ce moment qu'il s'agissait d'une super méthode je vous laisse imaginer pourquoi tous plantait.
Chaque instance de la classe ITDataGraph est un noeud du graph ayant un id et un tableau d'enfants. Je veux que chaque instance connaissent l'entrée du graph (ou la racine pour ceux qui préfèrent) et partagent le même undoManager. Il faut également que chaque classe de l'appli puisse accéder à l'entrée du graph facilement.
Pour ne pas me trimbaler des références partout, j'ai mis l'entrée du graph en static (variable de classe). Si on résume, la classe ITDataGraph a deux rôles, elle produit des instances (les noeuds du graph) et elle manage l'entrée du graph pour offrir aux autres classes des fonctionnalités partagées...
Par exemple, n'importe qu'elle classe peut faire :
De plus chaque sous classe peut enregister des actions dans l'undoManager etc...
A cause de cette dualité ITDataGraph ne peut pas être un protocole (enfin je vois pas trop comment)...
L'idée c'est que chaque noeud du graphe est lui-même considéré comme un graph de même que ses fils etc...
Mais pourquoi le noe“ud d'un arbre a-t-il besoin de connaà®tre la racine ? ça sens le problème de conception non ? ???
Toutes les modifications de données sont faites sur des éléments du graph donc il me semblait logique que chaque noeud ait un lien vers un undoManager pour enregistrer ses modifications. Tu l'aurais mis où toi ?
Dans un sens, le graph représente la couche model de l'appli...
C'est pour ça que je parle de problème de conception... Pourquoi un noe“ud a-t-il besoin de connaà®tre la référence de l'entrée ?
Dans un arbre classique, un noe“ud connaà®t en général ses fils ; dans certains cas son père mais je n'ai jamais vu de cas où il avait besoin de connaà®tre la racine (et de fait tout l'arbre !).
Oui, c'est la couche Model ; et un UndoManager fait partie de la couche Controller :P
Soit j'aurais fait un singleton Controller gérant le UndoManager (et permettant de gérer le multi-thread facilement).
Soit j'aurais confié la gestion au delegate de l'application de classe Controller (s'il y a un nib) et fait une macro pour l'accès
#define UNDOMGR [(Controller*)[NSApp delegate] undoManager]
Merci pour le temps passé à m'aider, l'idée de l'appDelegate est pas mal je vais voir ça. ::)
Je suis retombé dessus par hasard :
http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocObjectsClasses.html#//apple_ref/doc/uid/TP30001163-CH11-TPXREF118
Ils parlent de n'utiliser que des méthodes de classe, donc oui, ça revient à faire des fonctions et un contexte.
réponse :
Je voulais juste remettre le morceau de doc qui parle de çaÂ
Tu peux le faire où tu veux, seulement faut faire gaffe
Si tu le fais dans init, un accès direct en static:
maVar=[MaClasse maVarStatic];
ne passera pas par init et la variable ne sera pas initialisée.