variables globales

bofybofy Membre
09:03 modifié dans API AppKit #1
Bonjour

Je définis un singleton Common qui doit(devrait) me permettre d'accéder aux mêmes variables depuis n'importe quel endroit de mon code.

Sur un menu item de connexion, je crée une fenêtre qui établit une connexion avec une BdD pgsql : pas problème, tout se passe (apparemment) bien (NSLog ok dans la console de xcode), notamment le setter de l'identification de la connexion à  la base de données, suivi d'un getter ok.
Sur un menu item de déconnexion, je crée une fenêtre, et là  plus rien ne marche : il semble qu'il n'y a plus rien de global dans mon Common : impossible de récupérer l'adresse de la connexion avec son type, ce qui marche ci-avant.

Le fait d'utiliser plusieurs fenêtres casse-t-il le Common ? Je dis ça pour voir, mais je n'y crois guère.

En fait, je pense que je n'ai pas tout compris dans les singletons. Quelqu'un pourrait-il m'expliquer (la doc apple est pingre à  cet égard).

Merci

Réponses

  • schlumschlum Membre
    09:03 modifié #2
    La doc d'Apple est très claire, il n'y a rien à  ajouter  ???
    Qu'est-ce qui n'est pas clair ?

    AMHA tu gères mal ta mémoire, c'est ça le problème.
  • wiskywisky Membre
    09:03 modifié #3
    Fait tu tout les retain et release ?
    Le fait de faire trop de release d'un coup peut définitivement libérer ton singleton ce qui provoque un plantage lors de la tentative d'accès au singleton...


    PS : J'espère ne pas avoir dit de bêtise, mais avec la mémoire c'est souvent ça qui pose problème...
  • AliGatorAliGator Membre, Modérateur
    09:03 modifié #4
    Si tu as bien déclaré ton Singleton comme c'est expliqué en détail dans la doc Apple (il suffit de chercher "Singleton" dans la Doc Apple depuis Xcode par exemple) avec la surcharge du retain, retainCount, release et autorelease qu'ils montrent, tu ne devrais pas avoir de soucis côté mémoire.

    Il ne faut bien sûr dans ce cas pas appeler alloc/init pour créer ton singleton, mais ton accesseur spécialisé, comme tu utiliserais "defaultCenter" pour le singleton du NSNotificationCenter, ou "sharedInstance" pour la plupart des classes singleton qu'on trouve déjà  dans Cocoa... ou "sharedManager" dans le cas de l'exemple de code fourni par Apple.
  • bofybofy Membre
    09:03 modifié #5
    Merci

    Bien sûr j'applique la doc de singleton d'apple, dont je maintiens qu'elle est très succincte.

    Voici des extraits de mon code
    <br /><br />static RNKDPostgreSQLConnection * bofConn;<br /><br />@implementation Common<br />//...<br />//********--------<br />-(id) getConn {return bofConn;};<br />-(void) setConn : (RNKDPostgreSQLConnection *) conn { bofConn = conn;};<br />
    


    Dans ma 1ère fenêtre, j'appelle Common
    <br />//...<br />	Common * common = [Common sharedInstance];<br />//...<br />	extC =[RNKDPostgreSQLConnection connectionWithHost:[host field] ...			<br />	[common setConn:extC];<br />//...<br />	NSLog(@&quot;connect.in: [common getConn] : %@&quot;, [common getConn]);<br />
    


    Ca marche OK , cf dans la console xcode :
    <br />2008-12-08 17:00:58.330 tsib_18[3557:10b] connect.in: [common getConn] : RNKDPostgreSQLConnection: 0x1750c0&gt;<br />
    


    Dans ma 2ème fenêtre :
    <br />//...<br />	Common * common = [Common sharedInstance];<br />//...<br />	NSLog(@&quot;disconnectPG.in.getConn : %@&quot;,[common getConn]);<br />
    

    Plus rien ne marche, tout se passe comme si [common getConn] renvoyait n'importe quelle adresse, sauf celle définie dans la 1ère fenêtre : pour un vieux du C, cela me rappelle un problème de mémoire mal gérée. Faut-il mettre des retain, release, alloc, dealloc, autorelease, etc. Mais où ?

    Merci
  • Philippe49Philippe49 Membre
    09:03 modifié #6
    Faut-il mettre des retain, release, alloc, dealloc, autorelease, etc. Mais où ?
    Peut-être :
    -(void) setConn : (RNKDPostgreSQLConnection *) conn {
        if(conn!= bofConn) {
          [bofConn release];
          bofConn =[conn retain];
        }
    }
  • schlumschlum Membre
    09:03 modifié #7
    dans 1228754922:

    -(void) setConn : (RNKDPostgreSQLConnection *) conn {
         if(conn!= bofConn) {
           [bofConn release];
           bofConn =[conn retain];
         }
    }



    Rha, j'aime pas cette technique  :P

    -(void) setConn : (RNKDPostgreSQLConnection *) conn {<br />&nbsp; &nbsp; [conn retain];<br />&nbsp; &nbsp; [bofConn release];<br />&nbsp; &nbsp; bofConn = conn;<br />}
    


    C'est tellement plus élégant et ça évite un test qui ne sert à  rien 90,999% du temps !
  • Philippe49Philippe49 Membre
    09:03 modifié #8
    dans 1228767097:

    Rha, j'aime pas cette technique  :P

    Question de goût, sachons néammoins que c'est celle donnée par le script d'Apple (menu scripts>Code > Place Accessors Definitions on clipboard) Cela ne doit pas être si nul ...
  • schlumschlum Membre
    09:03 modifié #9
    Question de ne pas faire de choses inutiles surtout  ???
    Dans combien de cas sur 1000 tu fais un "set" avec le même objet qu'il y avait auparavant ?  :P

    Quand à  Apple, c'est pas une référence, ils aiment bien faire des trucs inutiles  :)
    Preuve en est leur code d'accès de singleton où ils font un lock de mutex à  chaque accès !

    + (MyGizmoClass*)sharedManager<br />{<br />&nbsp; &nbsp; @synchronized(self) {<br />&nbsp; &nbsp; &nbsp; &nbsp; if (sharedGizmoManager == nil) {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [[self alloc] init]; // assignment not done here<br />&nbsp; &nbsp; &nbsp; &nbsp; }<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; return sharedGizmoManager;<br />}
    


    Au lieu de le limiter par un test bien moins coûteux :

    + (MyGizmoClass*)sharedManager<br />{<br />&nbsp; &nbsp; if (sharedGizmoManager == nil) {<br />&nbsp; &nbsp; &nbsp; &nbsp; @synchronized(self) {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (sharedGizmoManager == nil) {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [[self alloc] init]; // assignment not done here<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br />&nbsp; &nbsp; &nbsp; &nbsp; }<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; return sharedGizmoManager;<br />}
    
  • Philippe49Philippe49 Membre
    09:03 modifié #10
    Ce sont des économies inutiles en général.
    Franchement l'une ou l'autre me semble parfaitement équivalent sauf pour une classe où j'utiliserais le setter 1000000 de fois, et où je pourrais gagner une microseconde ... ... mais là  je me poserais la question de la structure de mon programme.
  • schlumschlum Membre
    décembre 2008 modifié #11
    Ah ben ajoutons des tests inutiles un peu partout dans nos codes alors, puisque que ça ne fait perdre que quelques nanosecondes à  chaque fois, c'est pas trop grave  ;)

    C'est surtout parce qu'avec la technique du retain / release / affectation, on gagne en lisibilité (des accolades en moins), et on gagne une ligne  8--)
  • Philippe49Philippe49 Membre
    09:03 modifié #12
    Le test n'est pas plus inutile ici que de faire un retain puis un release sur le même objet ... car là  le temps perdu c'est le double  ;)
  • schlumschlum Membre
    décembre 2008 modifié #13
    Oh bien plus que le double, ce sont des affectations au lieu d'un test  ;)
    Mais je te mets au défi de trouver un cas pratique " intelligent " où ça arrive  :)

    Question de goût effectivement... Entre faire quelque chose d'inutile quasi-systématiquement, et quelque chose d'inutile un peu plus gros dans quelques cas rares, je préfère la seconde solution !  :fouf):
    (Surtout quand la syntaxe est plus élégante...)
  • Philippe49Philippe49 Membre
    09:03 modifié #14
    dans 1228776806:

    un cas pratique " intelligent " où ça arrive  :)

    Quand le setter prend en argument un objet s'apparentant aux "constantes" une NSString, un NSIndexPath, une NSImage en cache, une NSColor , NSFont  ...

    Ceci dit, je ne défends ni l'un ni l'autre, je dis que cela n'a pas d'importance, et que c'est couper les spaghetti dans le sens de la longueur, sauf cas rare ou mal ficelé.

  • schlumschlum Membre
    09:03 modifié #15
    Voui, des constantes soit, mais encore faut-il que l'objet qui y était déjà  soit le même !
    Concrètement, j'ai du mal à  voir les cas pratiques  :P
  • bofybofy Membre
    09:03 modifié #16
    Apparemment ça marche, mais je ne comprends pas pourquoi...

    1. Pourrais-tu m'expliquer les lignes retain et release ?
    2. Faut-il mettre ça dans tous les setter du singleton Common ?

    -(void) setConn : (RNKDPostgreSQLConnection *) conn {<br />&nbsp; &nbsp; [conn retain];<br />&nbsp; &nbsp; [bofConn release];<br />&nbsp; &nbsp; bofConn = conn;<br />}
    


    C'est tellement plus élégant et ça évite un test qui ne sert à  rien 90,999% du temps !
  • schlumschlum Membre
    09:03 modifié #17
    C'est un setter classique...
    On incrémente le compteur de références du nouveau, on décrémente celui de l'ancien.

    Pourquoi, tu faisais comment avant ?
  • bofybofy Membre
    09:03 modifié #18

    Ben, je faisais sans retain, ni release... Et ça marche ! sauf dans le cas cité.

    Explications STP  sur ce qu'est un "setter classique", je n'ai rien trouvé dans la doc.
     
    dans 1228834326:

    C'est un setter classique...
    On incrémente le compteur de références du nouveau, on décrémente celui de l'ancien.

    Pourquoi, tu faisais comment avant ?
  • AliGatorAliGator Membre, Modérateur
    09:03 modifié #19
    dans 1228917251:

    Ben, je faisais sans retain, ni release... Et ça marche ! sauf dans le cas cité.
    Ouch donc c'est un setter par "assign" et pas par "retain" ce qui peut te mener à  de belles surprises concernant la gestion mémoire... que tu as justement rencontré !
    dans 1228917251:
    Explications STP  sur ce qu'est un "setter classique", je n'ai rien trouvé dans la doc.
    Tout est décrit ici dans la doc Apple ; tout ce qui est autour de la gestion mémoire en Cocoa (cette doc et ses voisines), c'est une base qu'il est indispensable de connaà®tre si tu ne veux pas faire de bétises ou te retrouver avec des cas comme ceux que tu viens de citer, donc il peut être bon que tu y fasses un tour si tu ne te sens pas à  l'aise avec ces concepts ou petites subtilités.
  • schlumschlum Membre
    09:03 modifié #20
    dans 1228917251:
    Ben, je faisais sans retain, ni release... Et ça marche ! sauf dans le cas cité.


    Tu as probablement fait un "set" avec un objet auto-released... Du coup, il a été détruit peu après et quand tu as voulu y accéder, crash.
  • bofybofy Membre
    09:03 modifié #21
    Bon, terminé pour moi et merci à  tous.

    Je crois que je ne deviendrai jamais un pro de l'obj-C, ce qui n'est d'ailleurs pas mon but.

    Je vais mettre des retain et autres un peu partout, même si ne comprends pas complètement bien pourquoi.

    Par exemple, l'histoire de la laisse du chien (cité dans Hillegrass) me laisse rêveur : je n'ai jamais vu un chien avec plusieurs laisses tenues par des gens différents ! mais puisque ça sert de modèle...

    dans 1228919517:

    dans 1228917251:
    Ben, je faisais sans retain, ni release... Et ça marche ! sauf dans le cas cité.


    Tu as probablement fait un "set" avec un objet auto-released... Du coup, il a été détruit peu après et quand tu as voulu y accéder, crash.
  • AntilogAntilog Membre
    09:03 modifié #22
    Pourquoi terminé?  :crackboom:-

    Je ne pense pas que ce soit la bonne façon d'aborder le problème...

    La gestion de mémoire en Obj-C est assez simple en somme! Sauf si tu ne fais et ne feras qu'un seul programme (celui-ci) et que toi seul l'utilisera, il faudra bien t'y intéresser un jour... (en utilisant la méthode que tu nous décris, ton programme va probablement grossir à  l'utilisation, minutes après minutes)

    Même si l'analogie avec le chien et la laisse est un peu "capillo-tractée", elle est assez convaincante, il suffit d'imaginer le chien et les laisses multiples pour se rendre compte du principe...
    La programmation est un art demandant certaines qualités d'abstraction!
  • bofybofy Membre
    09:03 modifié #23
    Bon, puisque ce n'est pas terminé, j'aimerais comprendre pourquoi en programmation objet il faut gérer la mémoire ?

    C'est une régression qui nous ramène au C, et encore. J'ai écrit des milliers de lignes en C sans avoir à  me préoccuper de la mémoire: il suffisait de programmer correctement sans utiliser les "bidouilles" que le C permet.

    Aujourd'hui, il semble qu'en objective-C il faille passer impérativement par des bidouilles plus tordues les unes que les autres. Exemple parmi le plus grossier : pourquoi a= b est une affectation d'adresse et pas d'objet ?

    Somme toute, programmer en objective-C est du pur masochisme, imposé par apple, qui ainsi décourage tout développement individuel.

    Pourquoi pas ada qui manipule de vrais objets et pas des adresses ?

    La programmation objet est un petit monde qui permet à  des milliers d'informaticiens théoriciens de passer des thèses universitaires à  peu de frais en disséquant le sexe des anges, mais qui n'a jamais rien apporté aux programmeurs et qui introduit un monde d'instabilité qui explique les bugs récurrents de tous les systèmes et programmes informatiques.

    Bien à  toi

    PS : je suis masochiste...





    dans 1229101127:

    Pourquoi terminé?   :crackboom:-

    Je ne pense pas que ce soit la bonne façon d'aborder le problème...

    La gestion de mémoire en Obj-C est assez simple en somme! Sauf si tu ne fais et ne feras qu'un seul programme (celui-ci) et que toi seul l'utilisera, il faudra bien t'y intéresser un jour... (en utilisant la méthode que tu nous décris, ton programme va probablement grossir à  l'utilisation, minutes après minutes)

    Même si l'analogie avec le chien et la laisse est un peu "capillo-tractée", elle est assez convaincante, il suffit d'imaginer le chien et les laisses multiples pour se rendre compte du principe...
    La programmation est un art demandant certaines qualités d'abstraction!
  • schlumschlum Membre
    09:03 modifié #24
    dans 1230129782:

    Bon, puisque ce n'est pas terminé, j'aimerais comprendre pourquoi en programmation objet il faut gérer la mémoire ?


    Parce que c'est comme ça, ça a toujours été et ça le sera toujours. La gestion de la mémoire est une constante du métier de programmeur.
    Même en utilisant un GC, on n'est pas libre, car ça soulève d'autres problèmes (d'ordre par exemple).

    C'est une régression qui nous ramène au C, et encore. J'ai écrit des milliers de lignes en C sans avoir à  me préoccuper de la mémoire: il suffisait de programmer correctement sans utiliser les "bidouilles" que le C permet.


    C'est que tu n'as pas dû travailler avec des données sérieuses... Si tu bosses sur une image par exemple, tu la stockes sur la pile ? Il va faire la gueule ton programme !
    On n'est plus à  l'époque du Fortran où on était obligé de gérer le traitement des données avec des découpages super-optimisés pour la mémoire.

    Aujourd'hui, il semble qu'en objective-C il faille passer impérativement par des bidouilles plus tordues les unes que les autres. Exemple parmi le plus grossier : pourquoi a= b est une affectation d'adresse et pas d'objet ?


    Parce que l'Objective-C n'autorise pas la surcharge des opérateurs (ce qui est à  la fois une force et une faiblesse ; car la surcharge d'opérateurs permet de faire un peu tout et n'importe quoi)

    Somme toute, programmer en objective-C est du pur masochisme, imposé par apple, qui ainsi décourage tout développement individuel.


    C'est pas ce que se sont dit les milliers de développeurs qui s'y sont mis pour se faire des sous avec l'iPhone apparemment...

    Pourquoi pas ada qui manipule de vrais objets et pas des adresses ?


    Ben... Parce que c'est comme ça, que veux-tu qu'on dise  ???

    La programmation objet est un petit monde qui permet à  des milliers d'informaticiens théoriciens de passer des thèses universitaires à  peu de frais en disséquant le sexe des anges, mais qui n'a jamais rien apporté aux programmeurs et qui introduit un monde d'instabilité qui explique les bugs récurrents de tous les systèmes et programmes informatiques.


    Holà à à à à , ça sent la nostalgie ça... Les bugs récurrents ne sont pas dus à  la programmation objet, mais au laxisme actuel.
    C'est sûr que quand on utilisait les cartes perforées et que la machine mettait la journée à  compiler le programme, il valait mieux être sûr de son truc et l'avoir relu 15 fois, fait exécuter à  la main pour tous les cas etc. avant de l'envoyer !  :P
  • MalaMala Membre, Modérateur
    09:03 modifié #25
    dans 1230129782:

    J'ai écrit des milliers de lignes en C sans avoir à  me préoccuper de la mémoire: il suffisait de programmer correctement sans utiliser les "bidouilles" que le C permet.

    Certains de tes propos me laissent perplexes. ???

    Tu programmais quoi en C? L'allocation dynamique est l'une des bases du C. Tu n'as jamais utilisé d'alloc,calloc,malloc, free??? Et il en découle bien sûr l'usage des pointeurs qui rebutent tant les débutants en C.
  • schlumschlum Membre
    09:03 modifié #26
    dans 1230135371:

    dans 1230129782:

    J'ai écrit des milliers de lignes en C sans avoir à  me préoccuper de la mémoire: il suffisait de programmer correctement sans utiliser les "bidouilles" que le C permet.

    Certains de tes propos me laissent perplexes. ???

    Tu programmais quoi en C? L'allocation dynamique est l'une des bases du C. Tu n'as jamais utilisé d'alloc,calloc,malloc, free??? Et il en découle bien sûr l'usage des pointeurs qui rebutent tant les débutants en C.


    Ben il programmait peut-être en C comme en Fortan 77 (pas de pointeurs, gestion de mémoire uniquement sur la pile)  ;)
  • NoNo Membre
    09:03 modifié #27
    Il ne faut pas oublier que Obj-C n'est qu'une surcouche à  C : il en hérite à  100%.
    Donc Obj-C fait tout ce que C fait !

    On ne peut pas vraiment parler de régression, puisque Obj-C n'est pas vraiment un nouveau langage.
  • psychoh13psychoh13 Mothership Developer Membre
    09:03 modifié #28
    dans 1230135425:

    dans 1230135371:

    dans 1230129782:

    J'ai écrit des milliers de lignes en C sans avoir à  me préoccuper de la mémoire: il suffisait de programmer correctement sans utiliser les "bidouilles" que le C permet.

    Certains de tes propos me laissent perplexes. ???

    Tu programmais quoi en C? L'allocation dynamique est l'une des bases du C. Tu n'as jamais utilisé d'alloc,calloc,malloc, free??? Et il en découle bien sûr l'usage des pointeurs qui rebutent tant les débutants en C.


    Ben il programmait peut-être en C comme en Fortan 77 (pas de pointeurs, gestion de mémoire uniquement sur la pile)  ;)


    Bah pour moi, programmer uniquement sur la pile en C, c'est de la bidouille, utiliser des variables globales c'est aussi extrêmement crade... Et c'est zeuh bidouille en C...
  • schlumschlum Membre
    09:03 modifié #29
    dans 1230216379:

    Bah pour moi, programmer uniquement sur la pile en C, c'est de la bidouille, utiliser des variables globales c'est aussi extrêmement crade... Et c'est zeuh bidouille en C...


    Tu insultes les premiers programmeurs qui devaient développer des trésors d'ingéniosité pour résoudre des problèmes avec ça... seule chose qu'ils avaient à  disposition  :P
  • psychoh13psychoh13 Mothership Developer Membre
    09:03 modifié #30
    Bah justement, grâce à  eux on se retrouve avec des logiciels écrits en cobol qui sont de tels usines à  gaz que personne n'osent y toucher de peur de tout foutre en l'air. :P

    Au passage, les puristes C vous direz qu'il n'existe ni pile ni tas en C. :P
  • schlumschlum Membre
    09:03 modifié #31
    Je déteste mettre le nez dans le code de quelqu'un d'autre... quelque soit le langage utilisé  :crackboom:-
Connectez-vous ou Inscrivez-vous pour répondre.