写在前面:
- Non-fragile 非脆弱性
- fragile 非脆弱性
- ivars 实例变量-instance variables的缩写
非脆弱[Non-fragile] 实例变量是现代版Objective-C的一个新功能,应用于iPhone和64位Mac上。它们提供给框架开发者更多的灵活性,且不会失去二进制的兼容性,为声明在类接口外的实例变量和属性实例变量的自动合成铺平了道路。
脆弱性(fragile)的基类问题
脆弱的实例变量是脆弱的基类问题的子集.在一些语言中,一个超类没有改变的话,也不用重新编译该类的所有子类。例如,添加数据成员或虚成员函数给一个C++的超类将破坏该类的任何子类的兼容性,即使被添加的成员对于子类是私有或不可见的也一样如此。
在传统的Objective-C中,方法大多都是非脆弱的,这要感谢动态消息派发。你能够自由的为父类增加方法,只要你的命名不冲突就好。但是Objective-C的实例变量在32-bit Mac是脆弱的。
32-bit Mac :脆弱的Objective-C ivars
话说你正在写为Mac OS X Leopard 写宠物商店的一个应用程序。你可能有一个NSView的子类PetShopView,在这个宠物商店里有小狗和小猫的数组。
NSView(Leopard) | data structure | PetShopView | data structure |
---|---|---|---|
0 | Class isa | 0 | Class isa |
4 | NSRect bounds | 4 | NSRect bouds |
20 | NSView *superview | 20 | NSView *superview |
24 | NSColor *bgColor | 24 | NSColor *bgColor |
28 | NSArray *kittens | ||
32 | NSArray *puppies |
然后Mac OS X Def Leopard 出现了新的multi-paw接口技术,AppKit 开发人员增加了一些paw-tracking 代码给NSView。
NSView(Leopard) | data structure | PetShopView | data structure |
---|---|---|---|
0 | Class isa | 0 | Class isa |
4 | NSRect bounds | 4 | NSRect bouds |
20 | NSView *superview | 20 | NSView *superview |
24 | NSColor *bgColor | 24 | NSColor *bgColor |
28 | NSSet *touchedPaws | 28 | |
32 | NSArray *puppies |
不幸的是,你的kittens 被fragile ivars 毁灭了。或者说,AppKit开发者们无论在Mac OS X 10.0 上选择任何实例变量都会陷入困境。
iPhone 和64-bit Mac:non-fragile Objective-C ivars
无论你或者AppKit的开发者都想做这样的事情。
NSView(Leopard) | data structure | PetShopView | data structure |
---|---|---|---|
0 | Class isa | 0 | Class isa |
4 | NSRect bounds | 4 | NSRect bouds |
20 | NSView *superview | 20 | NSView *superview |
24 | NSColor *bgColor | 24 | NSColor *bgColor |
28 | NSSet *touchedPaws | 28 | NSSet *touchedPaws |
32 | NSArray *kittens | ||
36 | NSArray *puppies |
这里,当PetShopView被编译的时候,运行时能够意识到现在的NSView比以前大。子类实例变量向下滑动响应,不用重新编译任何代码,kittens通过一个动态运行时保存。
如何工作
已经生成的代码对于传统的Objective-C 实例变量访问像一个C的结构体。ivar的偏移量是一个常量在编译时决定。新的ivar代码为每一个ivar创建一个包含到ivar的偏移的变量,所有的代码访问ivar用这个变量。在启动时,运行时发现superclass尺寸超了,它可以改变任何ivar的偏移量。
在这个pet shop 例子中,_OBJC_PetShopView_kittens 是28在编译时,但是在运行时,当它看到Def Leopard版本是,它变为32. 代码不需要重新编译,ivar增加的偏移量的性能消耗很小,这样,AppKit ,你和kittens都比较愉快。