iOS objc_msgSend 消息转发流程

截屏2021-08-07 下午5.31.47.png

前言

好好学习,不急不躁。每天进步一点点

上篇文章讲解消息动态决议,消息动态决议在函数方法未实现时,提供的补救措施。在动态决议之后,系统分别执行了forwardingTargetForSelectormethodSignatureForSelector这两个函数流程,这就是消息转发流程,接下来我们展开讲解,什么是消息转发流程。

消息转发

快速转发

查找imp流程进入forwardingTargetForSelector内部,但由于该类没有实现aSelector,所以程序依然会报错:

截屏2021-08-09 下午2.44.25.png

在上一篇文章中讲述了公共类的一点思路,那么我们在forwardingTargetForSelector函数中,进行SEL的重定向试试,执行其他类的SEL

截屏2021-08-09 下午2.49.57.png

QLYTeacher类实现了sayHi函数,将QLYPersonsayHi函数,重定向至QLYTeacher类,程序运行完全没有问题,并且代码清晰,不臃肿,很好的实现了公共函数抽取封装的思路:如果其他类未实现某方法,可以在公用类中实现,或直接在公用类中动态添加aSelector;

但如果在QLYTeacher中,也没有实现sayHi函数,程序继续报错,消息将执行到methodSignatureForSelector函数—-慢速转发流程中;

慢速转发

mansu.png

QLYPerson类实现慢速查找,系统还是崩溃,并切没有执行QLYPerson类的慢速查找流程;

原因:QLYPerson类实现快速查找,通过重定向至QLYTeacher,所以会执行QLYTeacher类的查找SEL的imp流程,然后执行QLYTeacher的动态决议,QLYTeacher类的快速查找流程,但由于QLYTeacher没有实现快速查找流程,所以直接崩溃在QLYTeacher内部;

所以,为了查看慢速流程,暂时先把QLYPerson类的快速查找流程屏蔽了;

慢速2.png

执行了慢速查找流程,但依然崩溃,这是因为,慢速查找流程,需要搭配另一个函数forwardInvocation一块执行,并且需要返回NSMethodSignature参数;

截屏2021-08-09 下午4.39.21.png

v@:: 默认的参数编码;type不能传空值,必须传入一个可识别的签名;

至此,慢速查找流程结束;但也没有任何的业务处理;同时,forwardInvocation仅是声明,它有什么用处呢?

  • forwardInvocation 的作用:存储慢速查找流程事务,等待下一次调用;

接下来查探一下,anInvocation是否存储当前流程;

截屏2021-08-09 下午5.09.22.png

慢速查找流程,就是为了兼容程序中的错误而存在的,如果调用了某个未实现的方法,但又不需要任何的业务处理,慢速查找流程,就会为了完善程序,从而帮我们规避这种错误而产生的系统崩溃,让我们的系统更加健全,完美;

所以,如果我们在NSObject基类中,实现了如此的慢速查找,那么就能规避全系统的崩溃;但是使用慢速查找流程,也表示执行了一套imp的查找流程,性能上有不少的消耗

转发流程

通过上面的内容,对消息转发的快速查找流程与慢速查找流程有了一定的了解,但是在底层,它的消息转发流程是怎样的呢?这需要我们继续探究;

通过崩溃信息,我们了解到崩溃是由于方法未找到而产生崩溃,使用bt指令,打印出整个堆栈的信息,可以看到崩溃信息是来自CoreFoundation框架的doesNotRecognizeSelector函数,并且在main函数之前执行了___forwarding____CF_forwarding_prep_0两个函数,所以我们着重来看下这几个函数的业务逻辑;

截屏2021-08-10 下午3.08.01.png

由于CoreFoundation框架未开源,想要了解消息转发原理,得用新工具:

  • 1、先下载Hopper Disassembler工具;
  • 2、获取CoreFoundation框架的可执行文件;
  • 3、使用Hopper Disassembler打开CoreFoundation框架的可执行文件;

接下来开启反汇编操作;

查询forwarding函数源码,顺着源码查看,底层思路先判断当前class是否存在,如果class不存在,则执行_objc_msgSend函数获取class,如果存在则执行_objc_msgSend_stret获取class,接着判断是否为taggedpointer小对象类型,然后进行一系列的位移操作,之后我们就能看到消息快速转发的逻辑forwardingTargetForSelector:

11-第 1 页.png

如果class无法响应快速转发流程,则执行慢速转发:

11-第 2 页.png

在底层执行的慢速转发函数,与之前设想的不一样,底层执行的是forwardStackInvocation:函数,而这个函数并没有体现在OC层面,而是底层才有的设计,所以这个函数注定无法响应,按照底层跳转逻辑,接下来将执行loc_64c19代码块逻辑:

11-第 3 页.png

总结

11-第 4 页.png

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享