Objective-C中的动态类型和返回值

zou*_*oul 4 objective-c dynamic-typing

我遇到了一个我无法理解的非常奇怪的行为.我有一个Texture类型contentWidth属性的类int.此类包含在Image具有width类型属性的类中int.所述widthImage计算简单地作为contentWidth底层质地:

- (int) width
{
    return texture.contentWidth;
}
Run Code Online (Sandbox Code Playgroud)

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

// image is of type ‘id’
int width = [image width];
int height = [image height];
Run Code Online (Sandbox Code Playgroud)

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


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

- (int) width
{
    const int w = texture.contentWidth;
    return w;
}
Run Code Online (Sandbox Code Playgroud)

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

- (void) foo
{
    int bar = [image width];
}
Run Code Online (Sandbox Code Playgroud)

......现在bar包含了NaN.


更新:嗯,得到它:

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

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

zou*_*oul 5

那好吧.如果您对发生这种情况的原因感兴趣,请参阅Objective-C编程指南,第8章,返回和参数类型:

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

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

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