小码哥iOS学习笔记第十四天: 消息转发
一、消息转发
- 当一个对象调用方法时, 在底层会调用
objc_msgSend方法, 给消息接收者发送一条消息
- 在
objc_msgSend中, 一共可以分为三个阶段: 消息发送、动态方法解析、消息转发
消息发送流程如下图
二、消息转发的实现过程
- 查看源码, 可以看到当
动态方法解析也没有找到需要调用的方法实现时, 就会进入消息转发阶段, 调用_objc_msgForward_impcache函数
- 而在代码中, 实际调用的是
forwardingTargetForSelector:方法
1、准备代码
- 定义
Person类, 添加-test的方法声明, 但是不添加方法实现部分
2、方法调用
main函数中, 使用person调用test方法, 可以看到发生runtime错误
- 我们可以实现
-forwardingTargetForSelector:方法, 将消息接收者编程Cat的一个实例对象, 这样就会白test消息转发给Cat实例对象
- 此时, 就会调用
Cat中的-test方法
- 如果没有实现
-forwardingTargetForSelector:方法, 程序会继续调用-methodSignatureForSelector:方法
- 在
-methodSignatureForSelector:方法中设置好方法编码后, 就会调用-forwardInvocation:方法
NSInvocation类中封装了方法的调用, 通过打印可以看到方法的调用者和方法名
3、修改 消息接收者, 调用Cat实例的test方法
- 可以修改方法调用者(消息接收者), 并调用方法(发送消息)
4、修改调用的方法
- 将调用的方法修改为
-other, 运行程序, 可以看到调用成功
5、调用类方法
- 我们可以将消息转发给
[Cat class], 消息改为other, 就会调用Cat的类方法+other
6、调用带参数和返回值的方法
- 通过修改方法的指向, 调用自己的其他方法, 并拿到返回值
三、类方法的消息转发
- 上面的例子中展示的是实例方法的消息转发,
类对象也是可以做到消息转发
1、准备代码
main函数中, 只调用了[Person test]
- 执行程序, 会触发
runtime错误, 提示+test方法找不到
2、消息转发
- 可以再
+forwardingTargetForSelector:方法中设置消息转发的对象, 这里转发给[Cat class], 可以看到方法调用成功
- 因为
objc_msgSend的原理是给 消息接收者 发送 一条消息, 而这个消息是SEL类型的,并且不分是类方法(+)还是对象方法(-)
- 所以, 我们可以将
消息接收者设置为实例对象
- 可以看到, 上图中调用了
Cat中的-test方法
- 同样的, 如果不实现
+forwardingTargetForSelector:方法, 就会调用+methodSignatureForSelector:方法, 并调用+forwardInvocation:方法
四、消息转发的流程图