每个对象都有 isa 指针,指向对象所属的类。例如类 NSString 其实是类对象。
类对象产生于编译期,单例。
类对象有 isa 指针指向对应元类,元类
(metaclass)中保存了创建类对象
以及类方法
所需的所有信息。
struct objc_classs
结构体里存放的数据称为元数据(metadata)
。
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;
/* Use `Class` instead of `struct objc_class *` */
真正的源头
root class(meta)指向 Root class 类对象,Root class 类对象指向 nil,形成自闭环。
NSObject 就是 RootClass
总结:
- 实例对象(instance)的 isa 指向类对象(class)
- 类对象(class)的 isa 指向元类对象(meta-class)
- class 的 superclass指向父类的class
- meta-class的superclass指向父类的meta-class,根的 meta-class 的 superclass 指向根的class
- instance调用对象方法的轨迹:isa找到class,方法不存在,就通过superclass找父类
- class调用类方法的轨迹:isa找meta-class,方法不存在,就通过superclass找父类
方法调用相关
当调用对象方法时,实例对象内存并没有包含对象方法,而是通过它内部的isa指针找到它的类对象,从而在类对象中找到对象方法的实现进行调用。
当调用类方法时,类对象并没有类方法的信息,而是通过类对象的isa找到元类对象,最后找到类方法的实现进行调用
子类为什可以调用父类方法:
- 当实例对象调用对象方法会通过isa找到它的类对象,然后在类对象找方法实现,然而有时候这个类对象并没方法实现,那么就会通过superclass找到它的父类查找实现方法,一路找到基类。
- 当类调用类方法时会通过isa找到它的元类对象,然后在元类类对象找方法实现,然而有时候这个元类对象并没方法实现,那么就会通过superclass找到它的父元类查找实现方法,一路找到基类。