A propos de l'état initial d'un pointeur global

11:39 modifié dans API AppKit #1
Salut,

Dans le genre "question pour se prendre la tête pour rien" en voici une belle :

Lorsque l'on à  un pointeur style NSString *string dans le .h

et

- (void)setString:(NSString*)s
{
[string release];
[s release];
string=s;
}

Comment se fait il que [string release] ne fasse pas planter puisque le pointeur lors de la première utilisation de setString vaut n'importe quoi ? (par moment nil mais par obligatoirement)

Dois je faire un setString: nil ?

Est ce parce que le programme se voit allouer sa propre zone de mémoire et que le pointeur pointe la dedeans ne générant pas de crash ? :p

Bonne vendredi soir...

Réponses

  • Eddy58Eddy58 Membre
    octobre 2004 modifié #2
    Dans ton cas, si tu n'initialises pas ta NSString, son RetainCount sera logiquement à  0. Donc le [string release] devrait faire planter l'appli non ?
    Je sais pas pourquoi tu te prends la tête avec des trucs aussi tordus ;), mais en tout cas initialise ta string, tout simplement, avant de l'utiliser :)
    Il faut utiliser l'autorelease pour les méthode accesseurs. Dans ton cas :
    <br />-(void)setString:(NSString *)s<br />{<br />[string autorelease];<br />string=[s copy];<br />}<br />
    

    Voilà  :)
  • muqaddarmuqaddar Administrateur
    11:39 modifié #3
    Il faut utiliser l'autorelease dans les méthodes accesseurs


    Est-ce que :

    -(void)setString:(NSString *)s<br />{<br />[string autorelease];<br />string=[s copy];<br />}
    


    équivaut à  :

    -(void)setString:(NSString *)s<br />{<br />[s retain];<br />[string release];<br />string=s;<br />}
    


    ?
  • ChachaChacha Membre
    11:39 modifié #4
    Salut,
    Deux choses : d'abord la réponse à  ta question, ensuite des détails intéressant.

    D'abord, ta méthode s'appelant "setString", elle me fait penser que la NSString en question est une donnée membre d'un objet. Or, en Objective-C, contrairement à  C++, lorsqu'un objet est alloué par alloc, toutes ses données membres sont initialisées à  0. Donc initialement, ton pointeur de NSString vaut bien nil.

    Ensuite, Eddy58 soulève le problème de "eh là , attention, on ne fait pas n'importe quoi avec les release/retain", et il a proposé une des trois solutions données par Aaron Hillegas (monsieur Big Nerd Ranch) dans son bouquin "Cocoa programming for MacOS X".

    1)"retain, then release" : solution très élégante et efficace
    -(void)setString:(NSString*)s
    {
      [s retain]; //au cas où s == string
      [string release];
      string = s;
    }

    2)"Check before change" : ça oblige à  écrire un "if"
    -(void)setString:(NSString*)s
    {
      if (string != s)
      {
        [string release];
        string = [s retain];
      }
    }

    3)"Autorelease olds value" : deux lignes (génial), mais un peut moins performant que 1) et 2) à  cause du autorelease
    -(void)setString:(NSString*)s
    {
        [string autorelease];
        string = [s retain];
    }

    Il faut bien avoir compris la gestion de la mémoire en Objective-C pour saisir l'intérêt de ces techniques, comprendre pourquoi elles marchent, et pourquoi ce sont les seules valables.

    Voilà 

    Chachaaa
  • ChachaChacha Membre
    11:39 modifié #5
    Ah ben t'as posté penddant que je répondait.
    Au passage : je viens de relire le titre du fil de discussion : ta string est un pointeur global ? Ce n'est pas une donnée membre ? Dans ce cas rien ne t'empêche de l'initialiser à  nil lors de sa définition.
  • muqaddarmuqaddar Administrateur
    11:39 modifié #6
    Donnée membre , c'est le terme C++ non ?
    Tu parles bien de "variable d'instance" ou de "champ" là  ?
  • ClicCoolClicCool Membre
    octobre 2004 modifié #7
    dans 1098521389:

    Est-ce que :

    -(void)setString:(NSString *)s<br />{<br />[string autorelease];<br />string=[s copy];<br />}
    


    équivaut à  :

    -(void)setString:(NSString *)s<br />{<br />[s retain];<br />[string release];<br />string=s;<br />}
    


    ?


    pour ce qui est des retains et releases c'est équivalent.
    Le copy renvoie une copie implicitement retenue.

    La différence avec copy c'est que tu laisses l'objet transmis s vivre sa vie (vers un release ou vers une modification ...) et tu ne garde qu'une copie de s devenue indépendante de la source.

    Pour ce qui est de l'usage de release ou autorelease ça n'a aucune importance ici.
    L'usage de autorelease est interressant si l'objet à  releaser doit encore servir avant la fin du cycle d'exécution. (par exemple on le transmet à  une méthode)

    [EDIT] grilled
  • BruBru Membre
    11:39 modifié #8
    dans 1098466502:

    Comment se fait il que [string release] ne fasse pas planter puisque le pointeur lors de la première utilisation de setString vaut n'importe quoi ? (par moment nil mais par obligatoirement)
    Dois je faire un setString: nil ?


    Normalement, la méthode init de la classe doit se charger d'initialiser toutes les variables d'instance dans un état connu. Ca sert à  ça le init...

    Par exemple :
    [tt]
    - (id)init
    {
        if ([super init])
       {
            string=nil;
        }
        return self;
    }

    - (void)setString:(NSString *)s
    {
        if (string) [string release];
       string=[s retain];
       // ou encore mieux :
       string=[[NSString alloc] initWithString:s];
    }
    [/tt]

    On peut aussi initialiser string avec une chaine vide (string=[[NSString alloc] init]), ce qui supprime le test du nil dans le setString...

    .
  • ClicCoolClicCool Membre
    11:39 modifié #9
    dans 1098521875:

    3)"Autorelease olds value" : deux lignes (génial), mais un peut moins performant que 1) et 2) à  cause du autorelease
    -(void)setString:(NSString*)s
    {
        [string autorelease];
        string = [s retain];
    }


    ah ben oui, c'est pourtant évident ça !

    Merci Chacha :)

    PS c'est chacha ou Chacha avec majuscule initiale ?
  • ChachaChacha Membre
    11:39 modifié #10
    Ben normalement ça devrait être Chacha, mais la majuscule m'échappe souvent. Avec la prononciation de mon ex-binôme, ça fait quelque chose comme Chachaaa, mais on ne peut pas le deviner non plus.
  • ChachaChacha Membre
    11:39 modifié #11
    Une petite précision pour Bru :
    [release nil] est autorisé en Objective-C, donc pas besoin de faire de tests comme "if (string)". Ce n'est pas une facilité du compilateur, c'est vraiment le langage qui le permet.

    En C++, si je ne me trompe pas, "delete 0" est autorisé aussi, mais je crois qu'à  une certaine époque Visual ne le permettait pas. Alors c'est une habitude qui ne s'est pas répandue.
  • ChachaChacha Membre
    11:39 modifié #12
    Pour oxitan : oui oui, quand j'ai écrit donnée membre, je voulais dire variable d'instance (j'avais oublié le terme consacré en Objective-C). Donc on parle bien de la même chose.
  • muqaddarmuqaddar Administrateur
    octobre 2004 modifié #13
    Bru, tu conseilles fortement d'initialiser string à  nil ds le init ?
    Où ça sert à  pas grand chose ?
    Comme t'as dit "normalement" ...

  • cbrandtcbrandt Membre
    11:39 modifié #14
    dans 1098522666:

    dans 1098521389:

    Est-ce que :

    -(void)setString:(NSString *)s<br />{<br />[string autorelease];<br />string=[s copy];<br />}
    


    équivaut à  :

    -(void)setString:(NSString *)s<br />{<br />[s retain];<br />[string release];<br />string=s;<br />}
    


    ?


    pour ce qui est des retains et releases c'est équivalent.
    Le copy renvoie une copie implicitement retenue.

    La différence avec copy c'est que tu laisses l'objet transmis s vivre sa vie (vers un release ou vers une modification ...) et tu ne garde qu'une copie de s devenue indépendante de la source.

    Pour ce qui est de l'usage de release ou autorelease ça n'a aucune importance ici.
    L'usage de autorelease est interressant si l'objet à  releaser doit encore servir avant la fin du cycle d'exécution. (par exemple on le transmet à  une méthode)

    [EDIT] grilled


    NSString étant un objet immutable, pour optimiser, [s copy] est en fait un simple [s retain]... (mais c'est assez subtil, il faut bien l'avouer)
  • ClicCoolClicCool Membre
    11:39 modifié #15
    dans 1098533958:

    NSString étant un objet immutable, pour optimiser, [s copy] est en fait un simple [s retain]... (mais c'est assez subtil, il faut bien l'avouer)

    Pas si simple cbrandt

    Il est toujours possible que s soit à  l'origine un mutableString mais qui ici n'est transmis que sous string. Ca permet par ex de s'assurer que la méthode à  laquelle on transmet un objet mutable n'ait pas la possibilité de le modifier.

    Mais bon c'est assez subtile ;D
  • TiffTiff Membre
    11:39 modifié #16
    dans 1098524349:

    [release nil] est autorisé en Objective-C, donc pas besoin de faire de tests comme "if (string)". Ce n'est pas une facilité du compilateur, c'est vraiment le langage qui le permet.

    Oui, j'ai déjà  vu ça quelque part, ce qui fait que généralement les objets ont un release de plus que de retain ou init. Le premier release qu'il reçoivent alors qu'ils sont encore nil est accepté.
  • Eddy58Eddy58 Membre
    11:39 modifié #17
    dans 1098521875:

    Ensuite, Eddy58 soulève le problème de "eh là , attention, on ne fait pas n'importe quoi avec les release/retain", et il a proposé une des trois solutions données par Aaron Hillegas (monsieur Big Nerd Ranch) dans son bouquin "Cocoa programming for MacOS X".


    J'ai appris la technique avec l'autorelease dans "Learning Cocoa". La technique "retain, then release", est pas mal non plus ! D'ailleurs j'ai regardé dans "Programming Cocoa", il ne parlent que de celle-là .... :)
  • BruBru Membre
    11:39 modifié #18
    Eh oui, l'héritage (NSMutableString héritant de NSString), c'est subtil !

    Pour la petite histoire, dans la version 10.0 de OS X, le titre d'une fenête (méthode setTitle:) ne faisant qu'un retain sur la NSString passée en paramètre.

    Or de nombreux programmeurs se sont plaints car cette NSString était une NSMutableString qui servait aussi à  d'autre chose dans les programmes, et qui souvent évoluait... Ce qui faisait changer le titre de la fenêtre !

    L'un des fix de la 10.1 a été de faire une copie de la NSString passée en paramètre pour le titre de la fenêtre...

    .
Connectez-vous ou Inscrivez-vous pour répondre.