2009-09-12 8 views
4

Je suis tombé sur un problème étrange aujourd'hui. J'ai créé une sous-classe de UIView et ajouté seulement 1 méthode au code de modèle fourni par xcode.Sous-classement et diffusion dans l'objectif C

@interface FloatView : UIView { 

} 
- (void)floatTest:(CGFloat)x; 
@end 

- (void)floatTest:(CGFloat)x { 
    NSLog(@"float was %f", x); 
} 

Puis dans mon appDelegate j'avais code comme ceci:

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 imprime "0.000000".

Je me suis battu avec cela pendant des heures, en essayant de comprendre ce que je faisais mal, puis je l'ai changé le code dans mon appDelegate à

FloatView *floatView = [[FloatView alloc] init]; 
[floatView floatTest:10.0f]; 

Alors seulement, at-il imprimer l'attendu « 10.0000 » . Pourquoi cela est-il ainsi? J'ai déclaré FloatView en tant que sous-classe de UIView, ne devrais-je pas être en mesure d'attribuer un objet FloatView à un pointeur UIView sans problèmes?

Même si floatView a été déclaré pointeur vers un UIView, c'est vraiment un floatView et il devrait être capable de gérer le message floatTest? Suis-je complètement hors de la base ici?

+0

Votre code a généré un avertissement de compilateur, non? Si vous aviez compris pourquoi, vous auriez réglé le problème. – bbum

+0

Cela aurait pu régler le problème, mais je n'aurais probablement pas compris pourquoi il se comportait comme ça. Votre commentaire n'est vraiment pas utile. Mes remerciements à Mehrdad Afshari pour la réponse détaillée. –

Répondre

11

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). La chose est, tandis que votre instance répond réellement au message testFloat:10.0f, puisque le compilateur ne peut pas voir la déclaration de méthode de manière statique (comme la classe UIView ne déclare pas une telle méthode), il suppose que votre méthode prend ... comme argument et retourne id. Lorsque CGFloat est passé à une méthode qui attend le nombre variable d'arguments (...), il est promu à double. Ainsi, la méthode de réception reçoit un argument double et pense qu'il s'agit d'un float et qu'il n'est pas imprimé correctement.

Vous pouvez vérifier ce comportement en changeant la ligne NSLog à:

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 vraiment attend CGFloat et ne pas promouvoir l'argument à double. Par conséquent, cela fonctionne correctement.

En outre, si UIView* contenait la déclaration de méthode qui prenait un CGFloat, le compilateur appelait 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 manquant.

Questions connexes