前言
IOS底层原理之动态方法决议中探究了动态方法决议。在动态决议之后,通过日志辅助功能认识到forwardingTargetForSelector
和methodSignatureForSelector
方法,也就是消息发送的最后一个流程消息转发
1.instrumentobjc
函数补充
为什么调用这个方法
应为只有设置objcMsgLogEnabled = true
下面的方法才会执行
执行 logMessageSend
方法
我们运行代码
通过/tmp/msgSends-%d
找到 private/tmp/msgSends-50620
找到这个文件
2.消息转发
消息发送在经过动态方法决议仍然没有查找到正真的方法实现,此时动态方法决议抛出imp = forward_imp
进入消息转发流程。转发流程分两步快速转发
和慢速转发
快速转发
forwardingTargetForSelector
含义是返回未识别消息重定向的对象,简单理解指定一个对象,让这个对象去接收这个消息
我们运行[person sayhello]
方法 person
并没有实现sayhello
方法 给LGPerson
类添 加forwardingTargetForSelector
运行查看结果
先调用的 forwardingTargetForSelector
打印的结果 然后崩溃的 我们让LGStudent
添加sayhello
在 forwardingTargetForSelector
添加代码运行
方法查找本身是sel
查找imp
的过程 我们通过objc_msgSend
的cache
去找 没找到 去慢速查找methodlist
里面去找 没找到 动态方法决议里面找 没找到 直接告诉我哪个类有这个方法找个背锅侠也可以 如果我们LGStudent
也没是找不到sayhello
怎么办呢 接下来走 methodSignatureForSelector
慢速转发
慢速转发methodSignatureForSelector
也是消息查找的最后一个流程。给了动态方法决议,给了快速转发,在给你次慢速转发的机会
methodSignatureForSelector
的含义是返回一个NSMethodSignature
对象,该对象包含由给定选择器标识的方法的描述。methodSignatureForSelector
一般搭配和forwardInvocation
使用,如果methodSignatureForSelector
方法返回的是一个nil
就不会调用forwardInvocation
此时methodSignatureForSelector
的返回值是nil
,慢速转发完成,直接奔溃
此时我们加上方法签名 看是否调用forwardInvocation
如果methodSignatureForSelector
的返回值是NSMethodSignature
对象,则会调用forwardInvocation
进行实物处理anInvocation
保存了NSMethodSignature
签名信息,还有目标方法的方法签名sel
,以及方法的接收者。此时不会报奔溃信息,当然也可以处理anInvocaion
事务
anInvocation
的target
是[LGStudent alloc]
,anInvocation
的selector
是@selector(sayHello2)
,[anInvocation invoke]
触发消息的调用。forwardInvocation
方法就像一个不能识别的消息的分发中心,它能够将一个消息翻译成另外一个消息,或者简单的”吃掉“某些消息。所以不处理也不会崩溃
反汇编
方法调用奔溃,堆栈信息显示从__forwarding_prep_0___
往下调用最后又调用了doesNotRecognizeSelector
。具体的流程探究下
__forwarding_prep_0___
是属于CoreFoundation
系统库的
CoreFoundation下载链接
下载CoreFoundation
库以后的代码,在源码中全局搜索并无发现,说明这块内容苹果并没有对外提供
3.hoper反汇编CF
Hopper
反汇编的工具,我们通过反汇编CoreFoundation
的可执行文件,去查找__forwarding_prep_0___
,CoreFoundation
的可执行文件怎么获取
image list
可以获取所有的镜像文件列表,查找到CoreFoundation
的文件路径
全局搜索__forwarding_prep_0___
,发现只有一个,且会调用__forwarding__
,进入__forwarding__
方法
- 如果
forwardingTargetForSelector
方法没有实现,跳转loc_116064
流程 - 如果
forwardingTargetForSelector
方法的返回值是nil,跳转loc_116064
流程
此时进入了慢速转发流程
- 如果
methodSignatureForSelector
没有实现直接跳转到loc_1163e3
流程 - 如果
methodSignatureForSelector
返回值等于nil
跳转到loc_11645e
流程 - 如果
methodSignatureForSelector
返回了签名信息的对象
loc_1163e3
流程:直接报错跳转到loc_116457
流程loc_116457
流程:doesNotRecognizeSelector
崩溃处理
loc_11645e
流程:doesNotRecognizeSelector
崩溃处理
返回签名信息forwardInvocation
方法处理事务