1、isa指针

1.1、思考消息发送过程

方法调用举例

  1. Person *person = [[Person alloc] init];
  2. [person instanceMethod]; // 实例对象方法
  3. [Person classMethod]; // 类方法

调用方法本质上是消息发送:

  1. objc_msgSend(person, @selector(instanceMethod));
  2. objc_msgSend([Person class], @selector(classMethod));

实例方法保存在类对象里,实例对象里没有对象方法,消息如何发送?
类方法保存在元类对象里,类对象里没有类方法,消息如何发送?

1.2、isa指针指向

image.png
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指针的指向如下图所示

  1. @interface Person : NSObject
  2. - (void)personInstanceMethod;
  3. @end
  4. @interface Student : Person
  5. @end

image.png
当Student的instance对象要调用Person的对象方法时,会先通过isa找到Student的class,然后通过superclass找到Person的class,最后找到对象方法的实现进行调用。

2.2、meta-class对象的superclass指针

meta-class对象的superclass指针指向:
image.png
当Student的class要调用Person的类方法时,会先通过isa找到Student的meta-class,然后通过superclass找到Person的meta-class,最后找到类方法的实现进行调用。

3、总结

3.1、isa和superclass指向

以Student、Person、NSObject三个类为例:
image.png
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)才能和类/元类对象的地址相同
image.png
2、如何提取类对象的isa和superclass指针,可以新建一个结构体声明一个isa指针和superclass指针,强转成类对象,提取出isa和superclass指针。
3、类对象和元类对象在程序启动时创建,在程序退出时销毁。
4、实例对象中的成员变量保存了具体的值,类对象里的成员变量保存了信息。

4、类对象、元类对象在内存中结构

通过查看objc源码,class对象底层为objc_class结构体:
image.png

*class_rw_t中实际保存的类型是metho_array_t、property_array_t、protocol_array_t

如果想查看class/meta-class对象内部数据,可自行封装objc_class结构体,将class/mate-class对象强转为结构体,查看内部数据。(大神已经封装好了:MJClassInfo.h

  1. mj_objc_class *studentClass = (__bridge mj_objc_class *)([MJStudent class]);
  2. mj_objc_class *personClass = (__bridge mj_objc_class *)([MJPerson class]);
  3. class_rw_t *studentClassData = studentClass->data();
  4. class_rw_t *personClassData = personClass->data();
  5. class_rw_t *studentMetaClassData = studentClass->metaClass()->data();
  6. class_rw_t *personMetaClassData = personClass->metaClass()->data();