消息发送机制

objc_msgSend的具体流程如下:

通过isa指针找到所属类

查找类的cache列表

为什么会有cache列表呢

因为cache列表会提高效率

经常用的方法放到一个一个表里查的更快

如果没有则下一步

查找类的方法列表

如果能找到与选择子名称相符的方法,

就跳至其实现代码

找不到

就沿着继承体系继续向上查找

如果能找到与选择子名称相符的方法

就跳至其实现代码

实在找不到执行消息转发

就像BUG一样

找不到就甩锅给其他人

消息转发的流程如下

动态方法解析

先问接收者所属的类

你看能不能动态添加个方法来处理这个未知的消息

如果能

则消息转发结束

备用接收者

请接收者看看有没有其他对象能处理这条消息

如果有

则把消息转给那个对象

消息转发结束

消息签名

这里会要求你返回一个消息签名

如果返回nil

则消息转发结束

完整的消息转发

备胎都搞不定了

那就只能把该消息相关的所有细节都封装到一个NSInvocation对象

再问接收者一次

快想办法把这个搞定了

到了这个地步如果还无法处理

消息转发机制也无能为力了

对象在收到无法解读的消息后

首先调用其所属类的这个类方法

1
2
3
4
// selector : 那个未知的选择子
// 返回YES则结束消息转发
// 返回NO则进入备胎
+ (BOOL)resolveInstanceMethod:(SEL)selector

假如尚未实现的方法不是实例方法而是类方法, 则会调用另一个方法resolveClassMethod:

动态方法解析失败, 则调用这个方法

1
2
3
// selector : 那个未知的消息
// 返回一个能响应该未知选择子的备胎对象
- (id)forwardingTargetForSelector:(SEL)selector

消息签名

备用接受者搞不定

这个方法就准备要被包装成一个NSInvocation对象

在这里要先返回一个方法签名

1
2
3
4
5
6
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
// NSMethodSignature : 该selector对应的方法签名
给接收者最后一次机会把这个方法处理了, 搞不定就直接程序崩溃!

- (void)forwardInvocation:(NSInvocation *)invocation
// invocation : 封装了与那条尚未处理的消息相关的所有细节的对象