消息转发

814 阅读3分钟

前言

上一篇我们探索了动态方法决议,那么如果我们没有在动态发方法决议中处理未实现的方法,还有其他的方法么?带着疑问我们继续分析源码,首先在找到方法时候会进行log_and_fill_cache,我们进入到这个方法中查看,如图:

20211208215029.jpg 这里主要有2个方法logMessageSendinsertinsert在前面的说过,是插入方法。那么这个logMessageSend是做什么的呢?我们再次进入,如图:

20211208215746.jpg 在这个方法中注释这 create/open the log file创建或者打开日志文件,且objcMsgLogFD的值为-1,所以这个方法必然会打开日志文件。但是objcMsgLogEnabled = false,全局搜索objcMsgLogEnabled,结果如下:

20211208222137.jpg

浏览之后发现只有在instrumentObjcMessageSends会对objcMsgLogEnabled赋值false以外的值,如图:

20211208222242.jpg

所以我们对instrumentObjcMessageSends进行拓展,然后在外部就可以控制objcMsgLogEnabled的值。如图:

20211208222612.jpg

再次运行程序,崩溃,然后前往文件夹tmp/msgSendslogMessageSend 创建的目录),成功地找到了相关文件,打开如图:

20211208223059.jpg

消息转发

我们通过logMessageSend生成的文件发现在2次resolveInstanceMethod中间插入了forwardingTargetForSelectormethodSignatureForSelector这2个方法时干什么的?我们不得而知。全局搜索也只能看到一些声明和空实现,如图:

20211208224914.jpg

如何查找呢?打开Developer Documentation,如图所示:

20211208225340.jpg

快捷键shift + command + 0,打开后搜索forwardingTargetForSelectormethodSignatureForSelector

1、forwardingTargetForSelector

forwardingTargetForSelector 的搜索结果如下:

20211208225711.jpg

返回一个接收未识别消息的对象,简单的说就是我没有实现这条消息,但是我可以通过这个方法指定一个实例对象来处理这条消息(甩锅哦!)。我们来尝试一下,如图:

20211209085918.jpg

20211209085932.jpg

forwardingTargetForSelector中返回LGPerson的一个实例对象对象,然后再运行,如图:

20211209090253.jpg 调用Person实例的sayWork,没崩溃,而且打印出来 -[LGPerson sayWork],说明我们成功的把锅甩给了LGPerson。这个种甩锅的过程叫做快速转发

2、methodSignatureForSelector

methodSignatureForSelector的搜索结果:

20211209102509.jpg

这里好像没说具体的功能,往下翻:

20211209103438.jpg

大概意思:返回一个NSMethodSignature对象,该对象包含由给定选择器标识的方法的描述。 再点击- methodSignatureForSelector:如图:

20211209104706.jpg

大概意思是 返回一个NSMethodSignature对象,该对象包含由给定选择器标识的方法的描述。 我们尝试写一下这个方法:

20211209141743.jpg

运行程序,发现还是崩了,如图:

20211209141859.jpg 但是走了methodSignatureForSelector,那如何处理才能不崩溃?我们继续看描述:

20211209104720.jpg

这里有个相关的方法forwardInvocation,描述如下:

20211209142850.jpg

我们看到这个 Important的内容,大概意思就是重写这个方法必须先重写methodSignatureForSelector,我们已经重写了,所以写入这个方法试试,如图:

20211209143759.jpg

然后运行程序,如图:

20211209143855.jpg

我们清楚的看到sayWorkforwardInvocation中打印出来,我们又一次处理了未实现方法的崩溃处理。这种处理消息imp找不到的方法叫做慢速查找

总结

结合前面2片文章runtime和方法的本质动态方法决议,完整的消息查找流程就完善了。