从 Objective-C 对象到 Runtime (OC 对象模型)
isa 指针
Ojbective-C 中每个对象都有一个标明自己是什么对象的指针 – isa , 意为 “is a xxx”。 每一个类描述了一系列它的实例的特点,包括成员变量的列表,成员函数的列表等。下面是 Objective-C 非 2.0 版模型结构:
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char \*name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list \*ivars OBJC2_UNAVAILABLE;
struct objc_method_list \*\*methodLists OBJC2_UNAVAILABLE;
struct objc_cache \*cache OBJC2_UNAVAILABLE;
struct objc_protocol_list \*protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
那么这里的 isa 到底指向哪呢?
由于 Objective-C 中,一个类也是一个对象,所以它也必须是另一个类的实例,这个类就是元类 (metaclass) 。 元类保存了类方法的列表。当一个类方法被调用时,元类会首先找到本身是否有其实现,如果没有则向父类中查找。
元类也是一个对象,元类的 isa 指针则指向根元类 (root metaclass) 。而根元类的 isa 指向自己,这样就完成了一次闭环。
为了清楚的描述继承和 isa 指向的关系,苹果在官方文档中也给出了一个图例:
实线箭头表示继承关系,而虚线则表示 isa 指针指向。
到这里我们就大概能概括:
给一个类发消息,找元类继承链,给一个类的实例发消息,找类继承链。 实例 isa 指向类, 类 isa 指向元类, 元类 isa 指向根元类, 根元类 isa 指向自己。
###成员
从上面的 Objective-C 对象模型中可以看到,除了 isa 指针外还有很多其他成员,比如标记父类的 super_class , 应该用来表示类名的 name 等等。
version 为一个 long 类型, 应该表示这个对象的版本号。 instance_size 应该表示这个类对象大概在内存中占用的大小,从这个非 2.0 的结构体来看再考虑内存对齐应该不会超过一百个字节。(不考虑成员指针指向对象所占用的内存)
####Ivar
OC 对象中的 ivars 是指向成员属性列表的指针,来看下这个 objc_ivar_list :
struct objc_ivar_list {
int ivar_count OBJC2_UNAVAILABLE;
#ifdef __LP64__
int space OBJC2_UNAVAILABLE;
#endif
/* variable length structure */
struct objc_ivar ivar_list[1] OBJC2_UNAVAILABLE;
}
有个数标记 ivar_count , 有空间标记 space 。
那么 ojbc_ivar 呢:
struct objc_ivar {
char *ivar_name OBJC2_UNAVAILABLE;
char *ivar_type OBJC2_UNAVAILABLE;
int ivar_offset OBJC2_UNAVAILABLE;
#ifdef __LP64__
int space OBJC2_UNAVAILABLE;
#endif
}
名称标记 ivar_name , 类型标记 ivar_type , 空间标记 space , 而 ivar_offset 应该和内存对齐机制有关。
####Method
OC对象中的 methodList 是指向实例变量列表的指针,来看下这个 objc_method_list :
struct objc_method_list {
struct objc_method_list *obsolete OBJC2_UNAVAILABLE;
int method_count OBJC2_UNAVAILABLE;
#ifdef __LP64__
int space OBJC2_UNAVAILABLE;
#endif
/* variable length structure */
struct objc_method method_list[1] OBJC2_UNAVAILABLE;
}
obsolete 根据名字来猜,指向废弃的函数列表, method_count 是函数个数, space 为空间大小,然后继续来看下 objc_method :
struct objc_method {
SEL method_name OBJC2_UNAVAILABLE;
char *method_types OBJC2_UNAVAILABLE;
IMP method_imp OBJC2_UNAVAILABLE;
} OBJC2_UNAVAILABLE;
函数选择器 method_name , 描述类型(包含参数类型以及返回值类型)的字符串 method_types 以及函数指针 method_imp 。
####Cache
OC 对象中的 cache 对象类型为 objc_cache 的结构体 :
struct objc_cache {
unsigned int mask /* total = mask + 1 */ OBJC2_UNAVAILABLE;
unsigned int occupied OBJC2_UNAVAILABLE;
Method buckets[1] OBJC2_UNAVAILABLE;
};
Cache 为方法调用的性能进行优化,通俗地讲,每当实例对象接收到一个消息时,它不会直接在 isa 指向的类的方法列表中遍历查找能够响应消息的方法,因为这样效率太低了,而是优先在 Cache 中查找。 Runtime 系统会把被调用的方法存到 Cache 中(理论上讲一个方法如果被调用,那么它有可能今后还会被调用),下次查找的时候效率更高。
####Protocol
OC 对象中的 protocols 表示遵循的协议列表, 类型为 objc_protocol_list :
struct objc_protocol_list {
struct objc_protocol_list *next;
long count;
Protocol *list[1];
};
指向下一个协议列表的指针 next ,表示个数的 count 以及协议列表 list[1], Protocol :
@interface Protocol : NSObject
@end
可以看到 Protocol 也是一个类,具体成员这里就不再一一赘述了。
– EOF –
以上为这篇博客全部内容,欢迎提出建议,个人联系方式详见 关于。