Gestion mémoire et Autorelease

beltbelt Membre
08:04 modifié dans API AppKit #1
Après lecture de différents articles consacrés à  la gestion de la mémoire sous cocoa, il semble que les objets alloués par des appels aux méthodes de classe (celles commençant par un "+") et dont le nom débute par le nom de la classe (moins le NS et avec la permière lettre en minuscule), sont automatiquement placées dans le autorelease pool.
( ex : méthode arrayWithObjects de NSArray).
Il me semble qu'il y en a beaucoup d'autres. Est-ce juste ?

D'après les différentes documentations, la libération de l'objet s'effectue "un peu après"  l'appel à  la méthode. Cela me paraà®t un peu vague. Quelqu'un a-t-il des quelques précisions sur ce sujet. Et d'ailleurs, par quel mécanisme s'effectue cette libération ? ( Y-a-t-il un Thread qui s'occupe de ça ? ) 

Réponses

  • BruBru Membre
    août 2005 modifié #2
    Ce que tu dis est exact.

    En fait, il n'y a que très peu de méthodes "+" (méthodes de classe) qui ne placent pas l'objet créé dans l'autoreleasepool. La plus connue est alloc, mais il y a aussi sharedInstance par exemple.

    Lorsque l'autoreleasepool est détruit, chaque objet qu'il contient reçoit alors un message release (ce qui peut mener à  la destruction de l'objet).

    Dans une appli cocoa basée sur l'ApplicationKit, pour simplifier, un autoreleasepool est créé au début de chaque boucle d'événement (grosso modo, lorsque l'application reçoit un événement), puis il est détruit à  la fin de cette boucle (quand l'événement a été traité). La durée de vie est donc très courte.

    EDIT : merci à  Renaud pour sa vigilence.

    .
  • AntilogAntilog Membre
    08:04 modifié #3
    dans 1124867259:

    Dans une appli cocoa basée sur l'ApplicationKit, pour simplifier, un autoreleasepool est créé au début de chaque boucle d'événement (grosso modo, lorsque l'application reçoit un événement), puis il est détruit à  la fin de cette boucle (quand l'événement a été traité). La durée de vie est donc très courte.
    []


    Toutefois, cette durée de vie est dans la plupart des cas suffisante (jusqu'à  la fin de l'exécution de la méthode, et de toutes celles appelées directement...)
  • GreensourceGreensource Membre
    08:04 modifié #4
    Je pense que c'est par ici que ma question ira bien.
    C'est justement à  propos de la libération de la mémoire. Dans mon code j'ai eu besoin de:
    UITouch* touch = [touches anyObject];<br />// On récupère la case qui a été touché<br />GWCase* selectedCase;<br />selectedCase = [self caseAtPoint:[touch locationInView:self]];
    

    Du coup je me dit: "Hey pti gars, oublie pas de libéré les objets créés à  la fin!"
    Ni une ni deux je fait:
    [touch release];<br />[selectedCase release]
    

    Et là  bam! Bad Access Error!
    Du coup j'ai l'impression qu'il se sont libéré tout seul les coco! Ca corresponderais à  ce que vous disiez plus haut? Me trompe-je?
  • Philippe49Philippe49 Membre
    08:04 modifié #5
    ben c'est logique : la variable touch reçoit deux release : un que tu fais et l'autre parce que touches est en autorelease. Quand à  selectedCase qui est le modèle de l'un de tes vues  (je suppose) il reçoit un release alors qu'il doit être avec un retainCount=1.
  • AliGatorAliGator Membre, Modérateur
    février 2009 modifié #6
    Oui, la règle est simple : ce n'est pas ton code qui a créé les objets touch, donc ce n'est pas à  toi de t'occuper de les releaser.
    Tu n'as mis nulle part un [touch retain] ou un [touch copy] ou encore un touch = [[UITouch alloc] init], donc tu n'as aucune raison d'écrire un [touch release].

    Et en fait c'est pareil pour ta selectedCase.
    - Soit caseAtPoint renvoie une GWCase qui est une variable d'instance de ton "self", qui n'a pas de raison d'être supprimée tant que self existe, et comme tu n'as fait nulle part de retain sur cette GWCase y'a pas de raison que tu fasses de release correspondant ici (si c'est une variable de classe tu as sans doute fait un alloc/init à  l'initialisation de ta classe, et y'a bien un release correspondant à  faire mais il est dans le dealloc donc ; dans ta méthode touchBegan où tu as mis le code cité tu n'as pas fait de alloc/retain/copy donc pas de release par contre)
    - Soit caseAtPoint renvoie un nouvel objet GWCase, mais qui si tu as bien fait les choses doit être en autorelease, c'est à  dire que das le code de caseAtPoint tu as un alloc/init qqpart qui crée ton objet GWCase si c'est le cas, mais tu dois alors aussi avoir un autorelease.

    En effet la règle est on ne peut plus simple : c'est celui qui fait le alloc, retain ou copy qui doit faire le release correspondant. Si c'est une variable de classe, alloc/init dans l'initialisation de ta classe et release correspondant dans le dealloc. Si c'est une variable locale de ton code, alloc/init au début du code quand tu crées ta variable donc, ben release dans ce même bloc de code quand tu n'as plus besoin de la variable. (Ou autorelease au lieu de release si tu dois renvoyer cette variable, pour dire "bon c'est à  moi de penser au release mais faut pas le faire tout de suite parce que le code qui m'a appelé veut que je lui retourne cette variable... mais tu penseras à  faire tout seul le release plus tard").

    ---

    C'est plutôt bien résumé à  cet endroit dans la doc, quand on y pense la règle est simple, si tu alloc/new/retain tu release/autorelease, sinon c'est pas à  toi de gérer, point barre ;)
    Tu as aussi des exemples pratiques, avec explications, de cas où il faut faire le release et ceux où il faut pas, c'est dans la même section de la doc, quelques chapitres plus haut, ici
Connectez-vous ou Inscrivez-vous pour répondre.