小码哥iOS学习笔记第十四天: 消息转发

1,090 阅读3分钟

一、消息转发

  • 当一个对象调用方法时, 在底层会调用objc_msgSend方法, 给消息接收者发送一条消息
  • objc_msgSend中, 一共可以分为三个阶段: 消息发送动态方法解析消息转发
  • 消息发送流程如下图

  • 动态方法解析流程如下图

  • 这节记录的是消息转发学习笔记

二、消息转发的实现过程

  • 查看源码, 可以看到当动态方法解析也没有找到需要调用的方法实现时, 就会进入消息转发阶段, 调用_objc_msgForward_impcache函数

  • 而在代码中, 实际调用的是forwardingTargetForSelector:方法

1、准备代码

  • 定义Person类, 添加-test的方法声明, 但是不添加方法实现部分

  • 定义Cat类, 实现-test-other方法

2、方法调用

  • main函数中, 使用person调用test方法, 可以看到发生runtime错误

  • 我们可以实现-forwardingTargetForSelector:方法, 将消息接收者编程Cat的一个实例对象, 这样就会白test消息转发给Cat实例对象
  • 此时, 就会调用Cat中的-test方法

  • 如果没有实现-forwardingTargetForSelector:方法, 程序会继续调用-methodSignatureForSelector:方法
  • -methodSignatureForSelector:方法中设置好方法编码后, 就会调用-forwardInvocation:方法

  • NSInvocation类中封装了方法的调用, 通过打印可以看到方法的调用者方法名

3、修改 消息接收者, 调用Cat实例的test方法

  • 可以修改方法调用者(消息接收者), 并调用方法(发送消息)

4、修改调用的方法

  • 将调用的方法修改为-other, 运行程序, 可以看到调用成功

5、调用类方法

  • 我们在Cat中添 加+other 方法

  • 我们可以将消息转发给[Cat class], 消息改为other, 就会调用Cat的类方法+other

6、调用带参数和返回值的方法

  • 还可以给方法添加参数和返回值

  • main函数中的方法如下

  • 可以拿到参数对应的值

  • 通过修改方法的指向, 调用自己的其他方法, 并拿到返回值

三、类方法的消息转发

  • 上面的例子中展示的是实例方法的消息转发, 类对象也是可以做到消息转发

1、准备代码

  • Person类中只有一个类方法+test的声明

  • Car类中有-test+test的声明和实现

  • main函数中, 只调用了[Person test]

  • 执行程序, 会触发runtime错误, 提示+test方法找不到

2、消息转发

  • 可以再+forwardingTargetForSelector:方法中设置消息转发的对象, 这里转发给[Cat class], 可以看到方法调用成功

  • 因为objc_msgSend的原理是给 消息接收者 发送 一条消息, 而这个消息是SEL类型的,并且不分是类方法(+)还是对象方法(-)
  • 所以, 我们可以将消息接收者设置为实例对象

  • 可以看到, 上图中调用了Cat中的-test方法
  • 同样的, 如果不实现+forwardingTargetForSelector:方法, 就会调用+methodSignatureForSelector:方法, 并调用+forwardInvocation:方法

四、消息转发的流程图