4

我遇到了一个非常奇怪的行为,我无法理解。我有一个Texture具有contentWidthtype 属性的类int。这个类被包装在一个Image具有widthtype 属性的类中int。的简单地计算为width底层纹理的 :ImagecontentWidth

- (int) width
{
    return texture.contentWidth;
}

现在ImageButton想要读取图像大小的类(通过组合,而不是继承)使用:

// image is of type ‘id’
int width = [image width];
int height = [image height];

问题是height变量设置得很好,而width变量包含NaN(–2147483648)。我检查了尺寸——它们大约是 200×100 左右,远未达到int极限。Xcode 调试器工具提示也Texture正确显示了这两个属性,只有在宽度通过两个访问器后,数字才会出现乱码。对象没有被释放。我错过了什么?


更新:我已经扩展了Image类中的访问器以查看问题的根源:

- (int) width
{
    const int w = texture.contentWidth;
    return w;
}

现在,当我在第一行中断时,w设置正确。我跳过,执行返回到调用函数:

- (void) foo
{
    int bar = [image width];
}

…现在bar包含NaN.


更新:嗯,明白了:

int foo = [image width]; // image is id, returns NaN
int bar = [(Image*) image width]; // correct value

image声明为id,这就是这里的重点。有人可以解释一下吗?我有一种感觉,我没有调用正确的width方法,但这里到底发生了什么?我总是尽可能严格地键入我的变量,但这里的id类型很方便。我不知道它会导致这样的错误。

4

2 回答 2

5

那好吧。如果您对为什么会发生这种情况感兴趣,请参阅 Objective-C 编程指南,第 8 章,返回和参数类型

通常,具有相同选择器(相同名称)的不同类中的方法也必须共享相同的返回和参数类型。此约束由编译器强加以允许动态绑定。因为消息接收器的类(以及有关它被要求执行的方法的特定类的详细信息)在编译时是未知的,所以编译器必须将所有具有相同名称的方法视为相同。当它为运行时系统准备有关方法返回和参数类型的信息时,它只为每个方法选择器创建一个方法描述。

但是,当消息被发送到静态类型对象时,编译器知道接收者的类。编译器可以访问有关方法的特定于类的信息。因此,消息摆脱了对其返回和参数类型的限制。

这是 GCC bugzilla 中的错误报告(以及相应的博客文章)。该行为不是错误,但也不是很友好,因为编译器不会警告您(至少在默认警告设置下不会)。

于 2009-07-11T09:42:55.273 回答
1

您的访问者不应该是:

- (int) width
{
    return [texture contentWidth];
}

纹理是实例变量吗?如果是,您是否在 init 方法或包装类中进行了 super 初始化?

于 2009-07-11T08:55:55.477 回答