在Objective-C的旧版本中,objc_class结构实现如下:
struct objc_class {
Class isa;
Class super_class;
const char *name;
long version;
long info;
long instance_size;
struct objc_ivar_list *ivars;
struct objc_method_list **methodLists;
struct objc_cache *cache;
struct objc_protocol_list *protocols;
};
因此,表示对象的结构存储指向对象类的指针,指向对象超类的指针,对象的类名,对象的版本,信息和实例大小,对象的实例变量列表,对象的方法列表,对象的缓存和对象的协议列表。在表示对象的结构中存在这些字段是非常容易理解的,因为它们中的每一个都存储有关该对象的信息。
然而,相同的struct objc_class的Objective-C 2.0实现是这样的:
struct objc_class {
Class isa;
};
因此,在这个版本的objc_class中,struct中只有一个字段:指向对象类结构的指针。
我的问题是,关于对象的其他信息是如何存储在Objective-C 2.0中的,因为结构中只有一个表示对象的字段?
答案 0 :(得分:7)
这一切都在新的(好的,不再那么新的)非脆弱的ABI。
基本上,不是像过去那样将iVar存储在结构体内(如果超类改变了它的iVar布局,它会破坏继承),编译器会将iVar重定向放入另一层,类似于运行时的objc_setAssociatedObject
。
这允许一些有趣的场景。请考虑以下事项:
@interface A { // part of libA.a
id var1;
int var2;
float var3;
}
@end
@interface B : A { // part of libB.a
id var4;
}
@end
现在,如果有一段时间,我们需要更改课程A
,我们确定我们需要var3
更精确(例如将其转换为long double
)?
在较旧的,脆弱的ABI中,我们会被搞砸,直到libB
的制造者更新。然而,有了这个新的,非脆弱的ABI,我们可以灵活地改变所有这些,而libB
仍然有用。
虽然理论上这可能会在几个周期内变慢,但它增加了在运行时查找iVars的更简单方法,更灵活的子类化以及对不同类型的iVars的支持(例如__weak
)。