我今天遇到了一个奇怪的问题。我创建了一个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.0000)。问题是,当您的实例实际响应 testFloat:10.0f 消息时,因为编译器无法静态地看到方法声明(因为 UIView 类没有声明这样的方法),它假定您的方法将 ... 作为参数并返回 id

CGFloat 传递给需要可变数量的参数( ... )的方法时,它会被提升为 double 。因此,接收方法传递一个 double 参数,并认为它是 float ,并且它没有正确打印。

您可以通过将 NSLog 行更改为:

来验证此行为
NSLog(@"%f", *(double*)&x);

当编译器将消息发送到 FloatView * 而不是 UIView * 时,它可以找到该方法的确切签名。它可以看到它真的需要 CGFloat 并且不会将参数提升为 double 。结果,它正常工作。

此外,如果 UIView * 包含带有 CGFloat 的方法声明,编译器将适当地调用该方法。总而言之,这不是多态性问题;这是一个缺少方法签名的问题。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top