1、isa指针
1.1、思考消息发送过程
方法调用举例
Person *person = [[Person alloc] init];
[person instanceMethod]; // 实例对象方法
[Person classMethod]; // 类方法
调用方法本质上是消息发送:
objc_msgSend(person, @selector(instanceMethod));
objc_msgSend([Person class], @selector(classMethod));
实例方法保存在类对象里,实例对象里没有对象方法,消息如何发送?
类方法保存在元类对象里,类对象里没有类方法,消息如何发送?
1.2、isa指针指向
instance的isa指向class,当调用对象方法时,通过instance的isa找到class,再找到对象方法的实现进行用。
class的isa指向meta-class,当调用类方法时,通过class的isa找到meta-class,再找到类方法的实现进行调用。
2、superclass指针
2.1 class对象的superclass指针
创建Person类继承于NSObject,创建Student类继承于Person,则superclass指针的指向如下图所示
@interface Person : NSObject
- (void)personInstanceMethod;
@end
@interface Student : Person
@end
当Student的instance对象要调用Person的对象方法时,会先通过isa找到Student的class,然后通过superclass找到Person的class,最后找到对象方法的实现进行调用。
2.2、meta-class对象的superclass指针
meta-class对象的superclass指针指向:
当Student的class要调用Person的类方法时,会先通过isa找到Student的meta-class,然后通过superclass找到Person的meta-class,最后找到类方法的实现进行调用。
3、总结
3.1、isa和superclass指向
以Student、Person、NSObject三个类为例:
isa:
instance的isa指向class
class的isa指向meta-class
meta-class的isa指向基类的meta-class
基类的meta-class的isa指向自己
superclass:
class的superclass指向父类的class
如果没有父类,superclass指针为nil
meta-class的superclass指向父类的meta-class
基类的meta-class的superclass指向基类的class
3.2、方法调用轨迹
instance调用对象方法的轨迹:
isa找到class,方法不存在,就通过superclass找父类。
class调用类方法的轨迹:
isa找到meta-class,方法不存在,就通过superclass找父类的meta-class,
如果基类中也不存在,则去基类的class对象中查找同名对象方法。
3.3、补充
1、isa指针需要进行一次位运算(&ISA_MASK)才能和类/元类对象的地址相同
2、如何提取类对象的isa和superclass指针,可以新建一个结构体声明一个isa指针和superclass指针,强转成类对象,提取出isa和superclass指针。
3、类对象和元类对象在程序启动时创建,在程序退出时销毁。
4、实例对象中的成员变量保存了具体的值,类对象里的成员变量保存了信息。
4、类对象、元类对象在内存中结构
通过查看objc源码,class对象底层为objc_class结构体:
*class_rw_t中实际保存的类型是metho_array_t、property_array_t、protocol_array_t
如果想查看class/meta-class对象内部数据,可自行封装objc_class结构体,将class/mate-class对象强转为结构体,查看内部数据。(大神已经封装好了:MJClassInfo.h)
mj_objc_class *studentClass = (__bridge mj_objc_class *)([MJStudent class]);
mj_objc_class *personClass = (__bridge mj_objc_class *)([MJPerson class]);
class_rw_t *studentClassData = studentClass->data();
class_rw_t *personClassData = personClass->data();
class_rw_t *studentMetaClassData = studentClass->metaClass()->data();
class_rw_t *personMetaClassData = personClass->metaClass()->data();