前言
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方法处理事务