Sous-classement et casting dans Objective C
-
06-07-2019 - |
Question
Je suis tombé sur un étrange problème aujourd'hui. J'ai créé une sous-classe de UIView et ajouté une seule méthode au code de modèle fourni par xcode.
@interface FloatView : UIView {
}
- (void)floatTest:(CGFloat)x;
@end
- (void)floatTest:(CGFloat)x {
NSLog(@"float was %f", x);
}
Ensuite, dans mon appDélégué, j'avais un code comme celui-ci:
UIView *floatView = [[FloatView alloc] init];
[floatView floatTest:10.0f];
Assez simple, non? Qu'est-ce que cela devrait imprimer? Je pensais que ce serait quelque chose comme "10.0000", mais non, il affiche "0.000000".
J'ai lutté avec cela pendant des heures, essayant de comprendre ce que je faisais mal, puis j'ai changé le code de mon appDelegate en
FloatView *floatView = [[FloatView alloc] init];
[floatView floatTest:10.0f];
Seulement alors, a-t-il imprimé le "10,0000" attendu. Pourquoi cela est-il ainsi? J'ai déclaré FloatView comme une sous-classe d'UIView. Ne devrais-je pas pouvoir affecter un objet FloatView à un pointeur UIView sans problème?
Même si floatView a été déclaré pointeur sur un UIView, il s’agit en réalité d’un floatView et devrait pouvoir gérer le message floatTest? Suis-je totalement hors de la base ici?
La solution
En fait, le polymorphisme fonctionne comme prévu. Si cela ne fonctionnait pas, rien n'aurait été imprimé (dans votre exemple, 0,0000 est en cours d'impression). En réalité, votre instance répond effectivement au message testFloat: 10.0f
, car le compilateur ne peut pas voir la déclaration de la méthode de manière statique (comme la classe UIView
ne le déclare pas). méthode), elle suppose que votre méthode prend ...
en argument et retourne id
.
Lorsque CGFloat
est passé à une méthode qui attend un nombre variable d'arguments ( ...
), il est promu en double
. Ainsi, la méthode de réception reçoit un argument double
et pense que c'est un float
et elle ne s'imprime pas correctement.
Vous pouvez vérifier ce problème en remplaçant la ligne NSLog
par:
NSLog(@"%f", *(double*)&x);
Lorsque le compilateur envoie le message à FloatView *
plutôt qu'à un UIView *
, il peut trouver la signature exacte de la méthode. Il peut voir qu'il attend réellement CGFloat
et ne favorise pas l'argument en double
. En conséquence, cela fonctionne correctement.
De plus, si UIView *
contenait la déclaration de la méthode prenant un CGFloat
, le compilateur appellerait la méthode de manière appropriée. Pour résumer, ce n'est pas un problème de polymorphisme; c'est un problème de signature de méthode manquante.