Gestion de la mémoire et variables d'instance

chaps31chaps31 Membre
16:18 modifié dans API AppKit #1
Bonjour à  tous,

Bon, visiblement je n'ai pas tout compris.. Si, si je vous assure...  :P

Mon problème :
Soit une classe avec un awakefromnib dans lequel entre autre j'initialise des variables d'instance de cette classe.
J'ai une variable d'instance  NSMutableString maVar.
Une action de l'utilisateur lui donne une valeur avec un setString:
Nouvelle action de l'utilisateur (donc appel à  une autre méthode) et là  maVar est vide.... ben c'est une variable d'instance de ma classe bon sang...

J'imagine que je m'emmêle encore dans la gestion de la mémoire... J'ai lu qu'il faut à  chaque fois que l'on attribue une valeur à  une variable d'instance faire un retain, ce que je n'avais pas fait. Je pensais que ça venait de là  donc j'ai rajouté un retain sur la variable utilisée comme argument du setString:
Ben non, ça marche pas ma variable d'instance une fois la méthode terminée revient à  "vide".

SOS, merci...

NB : Question subsidiaire, j'imagine que lorsque l'on change la valeur d'une variable d'instance, comme on fait un retain à  chaque fois il faut faire un release juste avant. Je ne l'ai pas fais en l'occurence pour le test.

Réponses

  • CéroceCéroce Membre, Modérateur
    16:18 modifié #2
    dans 1257332040:

    J'ai lu qu'il faut à  chaque fois que l'on attribue une valeur à  une variable d'instance faire un retain, ce que je n'avais pas fait.


    Non pas forcément. ça dépend si ta classe veut seulement garder une référence vers l'objet ou également s'assurer qu'il ne va pas être désalloué.
    C'est la différence entre (assign) et (retain) pour les propriétés. Mais il est vrai que c'est ce qu'on fera le plus souvent.

    dans 1257332040:

    NB : Question subsidiaire, j'imagine que lorsque l'on change la valeur d'une variable d'instance, comme on fait un retain à  chaque fois il faut faire un release juste avant. Je ne l'ai pas fais en l'occurence pour le test.

    Oui, exactement.

    J'ai commencé une série d'articles sur la gestion mémoire. Les prochaines épisodes arrivent bientôt.
  • ClicCoolClicCool Membre
    16:18 modifié #3
    Comment est implémenté ton setter (setMaVar) ?
  • AliGatorAliGator Membre, Modérateur
    16:18 modifié #4
    Coder les accessor methods en Cocoa


    Si tu as une méthode setString dans une classe, d'après les conventions de nommage, elle est sensée faire elle même le retain de la nouvelle chaà®ne et le release de l'ancienne. Donc si tu utilises [tt][maVar setString:s][/tt] tu n'as pas à  faire le retain sur s et le release sur l'ancienne valeur de maVar, setString le fait tout seul. C'est à  ça que servent les méthodes setter d'ailleurs, entre autres.

    C'est si tu faisais [tt]maVar = s[tt/] que là  il y aurait un problème de mémoire (il faudrait faire un retain de s d'abord, un release de maVar ensuite pour releaser l'ancienne valeur, et seulement enfin affecter s à  maVar... mais bon c'est précisément ce que fait un setter justement)

    Sinon qu'entends-tu par "maVar est vide" ? elle est égale à  une chaà®ne vide, ou elle est égale à  nil ?

    Un extrait du code concernant ta question aiderait à  y voir plus clair.
  • ClicCoolClicCool Membre
    16:18 modifié #5
    Il me semble, dans ce cas précis, qu'il n'y a pas de retain/release à  faire dans son setter dans la mesure ou sa variable d'instance est Mutable en fait.

    Faut juste muter son contenu aux changement de valeur.

    Par contre à  son initialisation première faut un retain, et dans le dealloc un release.

    Après, on peut se poser la question de la pertinence du choix d'un mutable pour une string et de l'encapsulation necessaire pour s'assurer qu'elle soit pas modifiée indument ailleurs que dans le setter.
    Le Getter pourrait par exemple ne renvoyer qu'une copie non mutable de la variable ... ?
  • chaps31chaps31 Membre
    16:18 modifié #6
    Merci vous avez répondu à  ma question, donc avec mon setString: je n'ai pas de retain à  faire... Il s'agit d'un id qui me permet d'accéder à  une fiche dans une base de donnée, donc tant que je me sers des données de cette fiche je veux garder ma variable, et qui peux être utilisée par plusieurs méthode, mais je peux au bout d'un moment aller chercher une autre fiche et donc l'id va varier il faut du mutable.

    Avec cette base je vais chercher si vraiment je continue de sécher je reviens, histoire d'éviter de trop faire de flood... ;)
  • chaps31chaps31 Membre
    16:18 modifié #7
    Hum... heu c'est quoi déjà  une variable "out of scope" ?
  • chaps31chaps31 Membre
    16:18 modifié #8
    Je relance le thread pour une question. Dans la doc d'apple il est dit que lorsque l'on attribue la valeur d'une variable interne à  une méthode à  une variable d'instance de la classe il faut faire un retain.

    Je trouvais ça bizarre, et puis je me suis dis que la variable d'instance continue d'exister après la fin de la méthode, alors que la variable interne à  la méthode non, ainsi la variable d'instance pointera sur un espace mémoire désalloué.

    Sauf si on utilise un setter qui fait tout seul un retain, donc pas besoin, j'ai compris ? Merci
  • AliGatorAliGator Membre, Modérateur
    16:18 modifié #9
    variable out of scope = variable hors du périmètre, c'est à  dire par exemple tu as déclaré une variable dans un bloc de code encadré par des accolades, une fois sorti de ce bloc la variable n'existe plus dans le "scope" courant, et donc tu ne peux plus y accéder.

    pour le retain c'est en effet normal qu'il faille le faire dans le cas que tu décris car en effet ta variable interne à  la méthode (variable locale, quoi) va justement devenir "out of scope" une fois que tu seras sorti de ta méthode, alors que la variable d'instance elle pourra être accédée hors de cette méthode.

    Par contre, avant d'affecter cette variable d'instance, qui contiendra toujours un objet qui sera "retain" justement par cette variable d'instance (puisque par principe elle est accessible tout le temps où la classe qui la contient existe), il faut penser à  faire un "release" sur l'ancienne valeur contenue dans cette variable d'instance. Pour équilibrer les appels retain/release sur les objets.

    Et en effet si tu passes par un setter, tout ça est fait tout seul, puisque le setter se charge de relâcher (release) l'ancienne valeur de la variable et de retenir (retain) la nouvelle.

    (De même, il faudra faire un release sur la variable d'instance, si elle a été affectée, quand l'objet qui la contient est détruit, mais ça ça se fait dans le dealloc et normalement tu l'as déjà  codé)
  • ClicCoolClicCool Membre
    16:18 modifié #10
    dans 1257458853:
    .../...
    Par contre, avant d'affecter cette variable d'instance, qui contiendra toujours un objet qui sera "retain" justement par cette variable d'instance (puisque par principe elle est accessible tout le temps où la classe qui la contient existe), il faut penser à  faire un "release" sur l'ancienne valeur contenue dans cette variable d'instance. Pour équilibrer les appels retain/release sur les objets..../...


    Juste pour le plaisir de pinailler, je dirais ici le temps où l'instance de la classe qui la contient existe ;)

    [EDIT] zut, 2 min trop tot !!!
  • psychoh13psychoh13 Mothership Developer Membre
    16:18 modifié #11
    SI tu crées un objet de type NSMutableString et que tu ne le modifies que par setString: ça n'a vraiment aucun intérêt. C'est tout sauf optimisé, parce que ça copie à  chaque fois le contenu de l'autre chaà®ne dans ta chaà®ne, ça pompe de l'espace pour rien (quand tu donnes une nouvelles chaà®nes qui est plus petites que la précédentes) ou alors ça alloue de la mémoire en plus (quand la nouvelle chaà®ne est plus grande), et puis ça ne protège pas la variable d'instance d'une modification non-voulue.

    Personnellement, je te conseille d'utiliser une simple NSString, et quand tu changes sa valeur tu fais un release de l'ancienne valeur et une copie de la nouvelle valeur.

    <br />// à  la place de cette méthode tu peux simplement écrie dans ton @interface (publique ou privée)<br />// @property(copy) NSString *identifier;<br />// Et dans ton @implementation: @synthesize identifier;<br />- (void)setIdentifier:(NSString *)value<br />{<br />&nbsp; &nbsp; if(identifier != value)<br />&nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp; &nbsp; [identifier release];<br />&nbsp; &nbsp; &nbsp; &nbsp; // si &quot;value&quot; représente une NSString, cela correspond à  un retain<br />&nbsp; &nbsp; &nbsp; &nbsp; identifier = [value copy];<br />&nbsp; &nbsp; }<br />}<br />- (IBAction)buttonClicked:(NSButton *)sender<br />{<br />&nbsp; &nbsp; [self setIdentifier: [identField stringValue]];<br />}<br />
    


    Avec ce code, si la valeur retournée par [identField stringValue] est une chaà®ne de caractères non-modifiable, envoyer le message -copy ne fera rien de plus qu'un retain, en revanche, si l'objet est modifiable (NSMutableString) il créera une nouvelle instance non-modifiable de cet objet.
  • ClicCoolClicCool Membre
    16:18 modifié #12
    +1
  • AliGatorAliGator Membre, Modérateur
    16:18 modifié #13
    +2
Connectez-vous ou Inscrivez-vous pour répondre.