我今天遇到了一个奇怪的问题。我创建了一个UIView的子类,并且只为xcode提供的模板代码添加了一个方法。
@interface FloatView : UIView {
}
- (void)floatTest:(CGFloat)x;
@end
- (void)floatTest:(CGFloat)x {
NSLog(@"float was %f", x);
}
然后在我的appDelegate中,我有这样的代码:
UIView *floatView = [[FloatView alloc] init];
[floatView floatTest:10.0f];
非常简单,对吧?这打印出来的是什么?我认为它会像“10.0000”,但不,它打印出“0.000000”。
我在这几个小时里挣扎,试图找出我做错了什么,然后我将appDelegate中的代码更改为
FloatView *floatView = [[FloatView alloc] init];
[floatView floatTest:10.0f];
只有这样,才打印出预期的“10.0000”。为什么会这样?我已经将FloatView声明为UIView的子类,我不应该将一个FloatView对象分配给UIView指针而不会出现问题吗?
即使floatView被声明为UIView的指针,它实际上是一个floatView,它应该能够处理floatTest消息吗?我完全不在这里吗?
答案 0 :(得分:11)
实际上,多态性正在按预期工作。如果它不起作用,则不会打印任何内容(在您的示例中,正在打印0.0000)。问题是,虽然你的实例实际上响应了testFloat:10.0f
消息,因为编译器不能静态地看到方法声明(因为UIView
类没有声明这样的方法),它假定你的方法将...
作为参数并返回id
。
当CGFloat
传递给需要可变数量的参数(...
)的方法时,它会被提升为double
。因此,接收方法传递double
参数并认为它是float
并且它没有正确打印。
您可以通过将NSLog
行更改为:
NSLog(@"%f", *(double*)&x);
当编译器将消息发送到FloatView*
而不是UIView*
时,它可以找到该方法的确切签名。它可以看到它真的期望CGFloat
并且不会将参数提升为double
。结果,它正常工作。
此外,如果UIView*
包含采用CGFloat
的方法声明,编译器将适当地调用该方法。总而言之,这不是多态性问题;这是一个缺少方法签名的问题。