isa指针的指向
- instance实例对象的isa指针指向class类对象
- 当调用对象方法时,通过instance对象的isa找到class,最后找到对象方法的实现进行调用。
- class类对象的isa指针指向meta-class元类对象
- 当调用类方法时,通过class类对象的isa找到meta-class,最后找到类方法的实现进行调用。
- ==所有meta-class对象的isa指针指向基类的元类对象==。
SuperClass指针
继承关系:Student -> Person -> NSObject
- 类对象的SuperClass指针
- 当Student的实例对象要调用Person的对象方法时,会先通过Student实例对象的isa指针找到Student的类对象,然后通过Student类对象的SuperClass指针找到Person的类对象,最后找到方法的实现进行调用。
- 元类对象的SuperClass指针
- 当Student的类对象调用Person的类方法时,会先通过Student类对象的isa指针找到Student的元类对象,然后通过Student元类对象的SuperClass指针找到Person的元类对象,最后找到方法的实现进行调用。
- ==基类的元类对象的superclass指针指向的是基类的类对象==
isa指针细节
从64bit开始,isa要进行一次位运算才能计算出真实地址。
从objc源码中可以查到ISA_MASK的相关信息
类对象和元类对象的结构
struct objc_class的结构
//源码
#define FAST_DATA_MASK 0x00007ffffffffff8UL
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_rw_t *data() const {
return bits.data();
}
class_rw_t* data() const {
return (class_rw_t *)(bits & FAST_DATA_MASK);//bits需要&FAST_DATA_MASK才能获取到class_rw_t数据
}
...函数
}
struct class_rw_t {
uint32_t flags;
uint32_t version;
const class_ro_t *ro;
method_array_t methods;
property_array_t properties;
protocol_array_t protocols;
Class firstSubclass;
Class nextSiblingClass;
};
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;
uint32_t reserved;
const uint8_t * ivarLayout;
const char * name;
method_list_t * baseMethodList;
protocol_list_t * baseProtocols;
const ivar_list_t * ivars;
const uint8_t * weakIvarLayout;
property_list_t *baseProperties;
};
细看两个结构体的成员变量会发现很多相同的地方,他们都存放着当前类的属性、实例变量、方法、协议等等。区别在于:class_ro_t存放的是编译期间就确定的;而class_rw_t是在runtime时才确定,它会先将class_ro_t的内容拷贝过去,然后再将当前类的分类的这些属性、方法等拷贝到其中。所以可以说class_rw_t是class_ro_t的超集,当然实际访问类的方法、属性等也都是访问的class_rw_t中的内容
- 类在内存中的位置是在编译期间决定的,在之后修改代码,也不会改变内存中的位置。
- 类的方法、属性以及协议在编译期间存放到了“错误”的位置,直到 realizeClass 执行之后,才放到了 class_rw_t 指向的只读区域 class_ro_t,这样我们即可以在运行时为 class_rw_t 添加方法,也不会影响类的只读结构。
- 在 class_ro_t 中的属性在运行期间就不能改变了,再添加方法时,会修改 class_rw_t 中的 methods 列表,而不是 class_ro_t 中的 baseMethods。