消息机制的关键在于编译器为类和对象生成的结构。每个类的结构中至少包括两个基本元素:
- 指向父类的指针。
- 类的方法表。方法表将方法选标和该类的方法实现的地址关联起来
新的对象被创建时,对象的第一个实例变量是一个指向 该对象的类结构的指针,叫做 isa。通过该指针,对象可以访问它对应的类以及相应的父类。
在苹果2006年发布objective-c 2.0 以后。
1. 类的结构图
- id 的定义:
typedef struct objc_object *id;
struct objc_object {
private:
isa_t isa;
}
union isa_t
{
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
Class cls;
uintptr_t bits;
}
id类型是一个只包含了一个isa_t类型的结构体。
- 类的定义:
typedef struct objc_class *Class;
struct objc_class : objc_object {
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
}
类class继承自id,所以也有一个isa指针。
从上图我们可以看到:
OC的对象都是c语言的结构体实现的,所有对象都包含一个isa_t类型的结构体。
OC中的类也是一个对象。
类除了isa_t结构外,还有3个成员变量:父类的指针superclass,方法缓存cache,类的数据class_data_bits_t。
2. isa_t
1.元类 meta-class
当一个对象的实例方法被调用,会通过isa找到相应的类,然后在该类的class_data_bits_t中去查找方法。
但是在我们调用类方法的时候,类对象的isa里面是什么呢?这里为了和对象查找方法的机制一致,遂引入了元类(meta-class)的概念。元类存储着一个类的所有类方法。每个类都会有一个单独的meta-class。
在引入元类之后,类对象和对象查找方法的机制就完全统一了:
对象的实例方法调用时,通过对象的 isa 在类中获取实例方法的实现。
类对象的类方法调用时,通过类的 isa 在元类中获取类方法的实现。
类的isa 指向 元类。
元类的isa直接指向NSObject的元类。
类的superclass指针指向父类, 元类的superclass指针指向父元类。
nsobject没有父类即superclass是nil。 nsobject的元类的superclass指向nsobject。
类对象和元类对象是唯一的。 是在main方法执行之前,从dyld到runtime之期间被创建的。
2.isa_t结构体的具体实现:
为了节省内存和提高执行效率,对于64位程序,苹果引入Tagged Pointer。
如果不支持tagged pointer,直接返回指向类(或者元类)的指针。
如果支持, 还包含了 是否包含关联对象,引用计数,是否被弱引用等信息。
3.cache
Cache的作用主要是为了优化方法调用的性能,对使用过的方法进行缓存,便于第二次查找。4.class_data_bits_t
存储类的方法、属性和遵循的协议等信息的地方.
ObjC 类中的属性、方法还有遵循的协议等信息都保存在 class_rw_t 中。
其中还有一个指向常量的指针 ro,其中存储了当前类在编译期就已经确定的属性、方法以及遵循的协议。