A propos de l'état initial d'un pointeur global
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 ?
Bonne vendredi soir...
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 ?
Bonne vendredi soir...
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
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 :
Voilà
Est-ce que :
équivaut à :
?
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
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.
Tu parles bien de "variable d'instance" ou de "champ" là ?
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
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...
.
ah ben oui, c'est pourtant évident ça !
Merci Chacha
PS c'est chacha ou Chacha avec majuscule initiale ?
[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.
Où ça sert à pas grand chose ?
Comme t'as dit "normalement" ...
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
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é.
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à ....
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...
.