我正在读一本关于对象的书。在谈到遗产时,这本书说:
方法使用self参数查找它们的实例变量 使用
Objective-C编译器知道实例变量的布局 一个对象,因为它已经看到了每个的@interface声明 这些课程。
有了这些重要的知识,编译器就可以生成要查找的代码 任何实例变量。
然后它说这会导致脆弱的基类问题:
编译器通过使用“基础加偏移”机制来发挥其魔力。
给定对象的基址 - 即第一个实例变量的第一个字节的内存位置 - 编译器可以通过向该地址添加偏移量来查找所有其他实例变量。
当您在方法中访问某个实例变量时,编译器会生成代码以获取自保持的值,并添加偏移量的值(在本例中为4)以指向存储变量值的位置。
这会导致长期出现问题。
这些偏移现在硬编码到编译器生成的程序中。
即使Apple的工程师想要向NSObject添加另一个实例变量,他们也不能,因为会改变所有实例变量偏移。
这称为脆弱的基类问题。
Apple已经使用Leopard引入的新64位Objective-C运行时解决了这个问题,它使用间接方式来确定ivar位置。
我不明白为什么在NSObject中添加实例变量会导致问题。
如果NSOject发生变化,我们不能只重新编译程序,以便偏移量发生变化吗?
编辑:如果我们不重新编译,现有代码会失败吗?
答案 0 :(得分:2)
如果Apple向NSObject
添加了一个ivar,所有的子类都需要重新编译,这意味着一个非常接近所有Objective-C代码的100%的数字
你现在看到问题吗?
解决这个问题并非不可能,只是需要让每个开发人员重新编译他们的代码库,但同时每个Objective-C程序都会被破坏。
作为进一步的参考,这是Greg Parker关于这个主题的一篇非常好的文章:http://www.sealiesoftware.com/blog/archive/2009/01/27/objc_explain_Non-fragile_ivars.html
答案 1 :(得分:2)
是的,重新编译可以解决问题,但在重新编译之前,您的程序将被破坏。
想象一下,您编译的应用程序定位到10.4。编译器查看NSObject的标题,并确定子类中每个ivar的适当偏移量。然后10.5出来,他们将新的ivars添加到NSObject。在10.5上运行你的应用程序的任何人都会遇到问题,因为Foundation框架(包括NSObject)是针对10.5 SDK编译的,而你的应用仍然依赖于10.4 SDK中的布局。
脆弱的基类问题意味着Apple无法更改任何框架类的大小而不会崩溃没有为新SDK重新编译的每个应用程序。在理想的世界中,开发人员总是会及时发布更新,这不是现实。因此,在脆弱的基类问题得到解决之前,Apple的双手并列。