我们先来解释一下苹果官方给开发者提供的这张图

例如我们创建个自己的类 LWPerson *person = [[LWPerson alloc] init];每个类都有自己的isa,它指向对应的了[LWPerson Class],[LWPerson Class]也有自己的isa,它则指向对应的元类meta;这里解释一下两个问题
Q : Instance(类对象),class(类),meta(即meta-class元类) 里面各存着这么
A : Instance 存着一个isa指向class,还存着自己的成员变量;class里存有isa,superclass,属性、对象方法、协议、成员变量等;meta里存在isa,superclass,类方法等;如图(图片引用自李明杰老师)

Q : 为什么isa要这样指来指去,这样有什么好处
A : 例如这段代码
LWPerson *person = [[LWPerson alloc] init];
person.age = 20;
persom.height = 180;
[person sing];
[person dance];
[person rap]; 其中age和height都是每个LWPerson私有的,每创建一个LWPerson都可能不一样,但是sing,dance,rap方法是每一个LWPerson共有。所以当创建LWPerson对象后,只需isa和成员变量,所有的方法都放在LWPerson的类里,对象通过isa找到对应类的的方法,这样可以大大的节省LWPerson对象所占用的内存。这里LWPerson类的isa指向LWPerson的元类,类方法就存在元类里,也很好的解释了一般情况下 类方法为什么不能使本身的成员变量,因为存在类对象上;
接回之前的继续说:每个类都存有一个superclass指针,这很好理解,子类如果找不到对应的方法,便会顺着superclass指针找到对应的父类。meta的也一样本身没有的类方法也会去寻找父类的类方法,这样一直一级一级往上传,一直传到Root Class, Root Class的元类比较特殊,苹果设计它的isa指向自己,superclass指向Root Class,如果Root Class也找不到方法,就会报一个我们很熟悉的错误 unrecognized selector sent to instance 0x600001a3a5b0
可能上面说的比较多比较乱,我们可以举个栗子再捋一次
首先,我们创建个类LWPerson继承于NSObject。
LWPerson *person = [[LWPerson alloc] init];在创建LWPerson的时候,我们用的[LWPerson alloc]本质就是 LWPerson类通过isa去meta里找类方法,但是找不到!就再通过meta的superclass找到它的父meta即NSObject的meta, NSObject的类方我们很容易就可以找到alloc。init也是同理,我们在[LWPerson alloc]后,它实际上返回的是一个LWPerson的对象,它本身也没有init对象方法,所以找它的父类NSObject 的对象方法init

我们也可以在LWPerson.h中声明一个-(void)sing方法,但不写实现,这样person对象就会去LWPerson的类里找sing方法,但没实现sing方法,就会顺着superclass去NSObject到对象方法,但NSObject也没有sing方法,所以继续往上找到了Root Class,但Root Class也没有sing方法,所以指向nil,系统报错 unrecognized selector sent to instance。
这就是方法系统调用的过程,当然还有不少更底层更细致的流程,篇幅原因就下次再细聊了
<p><br></p>