Effectivement, tu as raison, [super init] est suffisant. Perso je mets self=[super init]; parce que pour moi cela chante mieux, mais ce n'est pas obligatoire.
Personnellement, Philippe, je fais comme toi, j'ai conservé la forme idiomatique qu'on trouve depuis le début de Cocoa, même si elle ne me paraà®t plutôt moins naturelle.
En mettant - (id)initWithX:(CGFloat) xVal Y:(CGFloat)yVal comme dans CIVector, ça marche, on a bien le 5 et le 1. Y a forcément une erreur quelque part, il ne va pas chercher la signature de CIVector pour l'appliquer à Toto qui hérite de NSObject !
Si, ça doit être un truc du genre... Il bafouille sur les signatures ! Dans le fichier préprocessé, celui de CIVector apparaà®t avant l'autre :
Inquiétant quand même parce qu'à la sortie du alloc, la classe est bien Toto . Cela veut dire que l'imbrication de messages n'est pas équivalente à la succession des messages. C'est un énorme piège.
Enfin logique tu y vas fort... Il n'y a aucune logique là dedans
Qu'on l'appelle sur id, qu'il se mélange et rentre dans celle de CIVector, pourquoi pas. Mais là il rentre dans la bonne avec la mauvaise signature, c'est un peu nimp'
int main (int argc, const char * argv[])<br />{<br /> Toto *t = [Toto alloc];<br /> [(CIVector*)t initWithX:5 Y:1];<br /> [t printXY];<br /> [t release];<br /> return 0;<br />}
Il rentre dans le "initWithX:Y" de Toto avec la signature de CIVector... (et on obtient ce qu'on avait avec les deux sur une seule ligne). Surprenant je dois dire. Dangereux le dynamisme parfois !
Enfin j'arrive à y trouver une certaine logique. Cet appel va donner "objc_msgSend((id)t,@selector(initWithX:Y:),5,1)" (5 et 1 seront lus en tant que floats)
Comme le type de "t" est dans sa structure "objc_class", il va le reconnaà®tre comme "Toto" et va appeler la bonne méthode, mais les arguments vont être mal interprétés.
Et bien je pensais pas que c'était si dangereux (j'ai pas exactement tout saisi). Mais alors du coup, si je ne veux plus que cela arrive, n'aurais-je pas intérêt, lors du init de retourner, plutôt qu'un id un Toto? Et d'ailleurs cela m'amène à me poser une autre question (venant de java): pourquoi on ne renvois pas systématiquement le bon type? C'est pour pouvoir faire de la généricité?
Et bien je pensais pas que c'était si dangereux (j'ai pas exactement tout saisi). Mais alors du coup, si je ne veux plus que cela arrive, n'aurais-je pas intérêt, lors du init de retourner, plutôt qu'un id un Toto?
Non, renvoyer (id), c'est pour avoir un comportement correct lorsqu'une classe hérite d'une autre, et que l'on ne redéfinit pas la méthode d'initialisation, ce qui est très souvent le cas.
Avant d'utiliser le schéma [[UneClasse alloc] initWithMachin:unArgument]; il faut être sur qu'aucune autre classe ne définit une méthode initWithMachin: avec un argument différent de celui utilisé dans la méthode de UneClasse.
Si néammoins on veut garder initWithMachin: , séparer en deux phases t=[uneClasse alloc] suivi de [t initWithMachin:unArgument]; ou caster en t=[(UneClasse*) [UneClasse alloc] initWithMachin:unArgument];
Ok, je ferais attention à ça la prochaine fois. Mais c'est balèze de trouver si une méthode à déjà le même nom! J'aurais jamais réussi à trouver tout seul celle que vous avez trouvé.
Dans XCode 3, j'ai rajouté -Wstrict-selector-match dans Other Warning Flags et bingo !
Line Location AppController.m:61: warning: multiple methods named '-initWithX:Y:' found Line Location CIVector.h:45: warning: using '-(id)initWithX:(CGFloat)x Y:(CGFloat)y' Line Location ClasseEssai.h:22: warning: also found '-(id)initWithX:(int)x Y:(int)y'
Ok, je ferais attention à ça la prochaine fois. Mais c'est balèze de trouver si une méthode à déjà le même nom! J'aurais jamais réussi à trouver tout seul celle que vous avez trouvé.
Aucune difficulté : Tu tapes intWithX: dans le search field de la doc ... en faisant les réglages nécessaires. La lecture de la documentation est essentielle avec Objective-C.
Ah bas oui je suis bête. J'avais oublier que les méthodes apparaissaient aussi dans la doc! Elle est trop génial celle là quand je compare au reste n'empêche!
Ah bas oui je suis bête. J'avais oublier que les méthodes apparaissaient aussi dans la doc! Elle est trop génial celle là quand je compare au reste n'empêche!
Encore plus simple : Option+double clic sur le nom d'une méthode ouvre la doc associée Command+double clic sur le nom d'une méthode permet de s'y téléporter
Ah bas oui je suis bête. J'avais oublier que les méthodes apparaissaient aussi dans la doc! Elle est trop génial celle là quand je compare au reste n'empêche!
Dans XCode 3, j'ai rajouté -Wstrict-selector-match dans Other Warning Flags et bingo !
Line Location AppController.m:61: warning: multiple methods named '-initWithX:Y:' found Line Location CIVector.h:45: warning: using '-(id)initWithX:(CGFloat)x Y:(CGFloat)y' Line Location ClasseEssai.h:22: warning: also found '-(id)initWithX:(int)x Y:(int)y'
Dans XCode 3, j'ai rajouté -Wstrict-selector-match dans Other Warning Flags et bingo !
Line Location AppController.m:61: warning: multiple methods named '-initWithX:Y:' found Line Location CIVector.h:45: warning: using '-(id)initWithX:(CGFloat)x Y:(CGFloat)y' Line Location ClasseEssai.h:22: warning: also found '-(id)initWithX:(int)x Y:(int)y'
Mais avec Xcode 2.5, si la même option de compilation produit bien les mêmes warnings, le bug ne se produit pas.
Il y a donc bien un problème avec le compilateur dans Xcode 3.
Réponses
Un peu hors-sujet, mais voici un article sur ce point sur le blog de Wil Shipley:
http://www.wilshipley.com/blog/2005/07/self-stupid-init.html
Personnellement, Philippe, je fais comme toi, j'ai conservé la forme idiomatique qu'on trouve depuis le début de Cocoa, même si elle ne me paraà®t plutôt moins naturelle.
Si, ça doit être un truc du genre... Il bafouille sur les signatures !
Dans le fichier préprocessé, celui de CIVector apparaà®t avant l'autre :
Toto *t ;
t=[Toto alloc];
[t initWithX:5 Y:1];
Mais du coup, pourquoi passe-t-il dans la bonne (avec gdb) ?
% gcc pgm.m -o pgm -framework Cocoa
% pgm
2009-02-21 12:49:59.535 pgm[1337:10b] Toto
2009-02-21 12:49:59.536 pgm[1337:10b] xVal=5 , yVal=1 , x=5 , y=1
2009-02-21 12:49:59.537 pgm[1337:10b] 5,1
%
Cela veut dire que l'imbrication de messages n'est pas équivalente à la succession des messages. C'est un énorme piège.
Il n'y a aucune logique là dedans
Qu'on l'appelle sur id, qu'il se mélange et rentre dans celle de CIVector, pourquoi pas.
Mais là il rentre dans la bonne avec la mauvaise signature, c'est un peu nimp'
Oui je l'ai retiré depuis.
Il rentre dans le "initWithX:Y" de Toto avec la signature de CIVector... (et on obtient ce qu'on avait avec les deux sur une seule ligne).
Surprenant je dois dire. Dangereux le dynamisme parfois !
(et ce code ne produit aucun warning !)
Cet appel va donner "objc_msgSend((id)t,@selector(initWithX:Y:),5,1)" (5 et 1 seront lus en tant que floats)
Comme le type de "t" est dans sa structure "objc_class", il va le reconnaà®tre comme "Toto" et va appeler la bonne méthode, mais les arguments vont être mal interprétés.
Mais alors du coup, si je ne veux plus que cela arrive, n'aurais-je pas intérêt, lors du init de retourner, plutôt qu'un id un Toto?
Et d'ailleurs cela m'amène à me poser une autre question (venant de java): pourquoi on ne renvois pas systématiquement le bon type? C'est pour pouvoir faire de la généricité?
Non, renvoyer (id), c'est pour avoir un comportement correct lorsqu'une classe hérite d'une autre, et que l'on ne redéfinit pas la méthode d'initialisation, ce qui est très souvent le cas.
provoque l'écriture sans aucun Warning de
% gcc pgm2.m -o pgm -framework Foundation
% pgm
2009-02-21 16:15:39.704 pgm[1670:10b] 1084227584
%
alors que naturellement la partie décommentée fonctionne bien ...
Avant d'utiliser le schéma [[UneClasse alloc] initWithMachin:unArgument]; il faut être sur qu'aucune autre classe ne définit une méthode initWithMachin: avec un argument différent de celui utilisé dans la méthode de UneClasse.
Si néammoins on veut garder initWithMachin: , séparer en deux phases
t=[uneClasse alloc] suivi de [t initWithMachin:unArgument];
ou caster en
t=[(UneClasse*) [UneClasse alloc] initWithMachin:unArgument];
http://www.cocoabuilder.com/archive/message/cocoa/2005/6/22/139644
Dans XCode 3, j'ai rajouté -Wstrict-selector-match dans Other Warning Flags et bingo !
Line Location AppController.m:61: warning: multiple methods named '-initWithX:Y:' found
Line Location CIVector.h:45: warning: using '-(id)initWithX:(CGFloat)x Y:(CGFloat)y'
Line Location ClasseEssai.h:22: warning: also found '-(id)initWithX:(int)x Y:(int)y'
Aucune difficulté : Tu tapes intWithX: dans le search field de la doc ... en faisant les réglages nécessaires. La lecture de la documentation est essentielle avec Objective-C.
Encore plus simple :
Option+double clic sur le nom d'une méthode ouvre la doc associée
Command+double clic sur le nom d'une méthode permet de s'y téléporter
AppKiDo est encore mieux...
Mais avec Xcode 2.5, si la même option de compilation produit bien les mêmes warnings, le bug ne se produit pas.
Il y a donc bien un problème avec le compilateur dans Xcode 3.
Probablement dû aux changements du runtime...