OC底层原理11-消息转发

274 阅读3分钟

前言

IOS底层原理之动态方法决议中探究了动态方法决议。在动态决议之后,通过日志辅助功能认识到forwardingTargetForSelectormethodSignatureForSelector方法,也就是消息发送的最后一个流程消息转发

1.instrumentobjc函数补充

Xnip2021-07-11_21-20-03.jpg 为什么调用这个方法

Xnip2021-07-11_21-21-23.jpg 应为只有设置objcMsgLogEnabled = true 下面的方法才会执行

Xnip2021-07-11_21-21-00.jpg

执行 logMessageSend方法

Xnip2021-07-11_21-35-45.jpg

我们运行代码

Xnip2021-07-11_21-36-57.jpg

通过/tmp/msgSends-%d 找到 private/tmp/msgSends-50620找到这个文件

Xnip2021-07-11_21-39-40.jpg

2.消息转发

消息发送在经过动态方法决议仍然没有查找到正真的方法实现,此时动态方法决议抛出imp = forward_imp进入消息转发流程。转发流程分两步快速转发慢速转发

快速转发

Xnip2021-07-11_21-43-58.jpg forwardingTargetForSelector含义是返回未识别消息重定向的对象,简单理解指定一个对象,让这个对象去接收这个消息

我们运行[person sayhello]方法 person并没有实现sayhello方法 给LGPerson类添 加forwardingTargetForSelector 运行查看结果

Xnip2021-07-11_21-51-20.jpg

先调用的 forwardingTargetForSelector 打印的结果 然后崩溃的 我们让LGStudent添加sayhelloforwardingTargetForSelector添加代码运行

Xnip2021-07-11_21-53-42.jpg

方法查找本身是sel查找imp的过程 我们通过objc_msgSendcache去找 没找到 去慢速查找methodlist里面去找 没找到 动态方法决议里面找 没找到 直接告诉我哪个类有这个方法找个背锅侠也可以 如果我们LGStudent也没是找不到sayhello 怎么办呢 接下来走 methodSignatureForSelector

慢速转发

慢速转发methodSignatureForSelector也是消息查找的最后一个流程。给了动态方法决议,给了快速转发,在给你次慢速转发的机会 Xnip2021-07-11_22-01-13.jpg

Xnip2021-07-11_22-11-05.jpg methodSignatureForSelector的含义是返回一个NSMethodSignature对象,该对象包含由给定选择器标识的方法的描述。methodSignatureForSelector一般搭配和forwardInvocation使用,如果methodSignatureForSelector方法返回的是一个nil就不会调用forwardInvocation

Xnip2021-07-11_22-13-06.jpg 此时methodSignatureForSelector的返回值是nil,慢速转发完成,直接奔溃

此时我们加上方法签名 看是否调用forwardInvocation

Xnip2021-07-11_22-15-23.jpg 如果methodSignatureForSelector的返回值是NSMethodSignature对象,则会调用forwardInvocation进行实物处理anInvocation保存了NSMethodSignature签名信息,还有目标方法的方法签名sel,以及方法的接收者。此时不会报奔溃信息,当然也可以处理anInvocaion事务

Xnip2021-07-11_22-21-50.jpg

anInvocationtarget[LGStudent alloc]anInvocationselector@selector(sayHello2),[anInvocation invoke]触发消息的调用。forwardInvocation方法就像一个不能识别的消息的分发中心,它能够将一个消息翻译成另外一个消息,或者简单的"吃掉“某些消息。所以不处理也不会崩溃

反汇编

方法调用奔溃,堆栈信息显示从__forwarding_prep_0___往下调用最后又调用了doesNotRecognizeSelector。具体的流程探究下

Xnip2021-07-11_22-39-53.jpg

__forwarding_prep_0___是属于CoreFoundation系统库的 CoreFoundation下载链接 下载CoreFoundation库以后的代码,在源码中全局搜索并无发现,说明这块内容苹果并没有对外提供

3.hoper反汇编CF

Hopper反汇编的工具,我们通过反汇编CoreFoundation的可执行文件,去查找__forwarding_prep_0___CoreFoundation的可执行文件怎么获取

Xnip2021-07-11_23-05-11.jpg image list可以获取所有的镜像文件列表,查找到CoreFoundation的文件路径

Xnip2021-07-11_23-06-15.jpg

全局搜索__forwarding_prep_0___,发现只有一个,且会调用__forwarding__,进入__forwarding__方法

Xnip2021-07-11_23-10-00.jpg

  • 如果forwardingTargetForSelector方法没有实现,跳转 loc_116064流程
  • 如果forwardingTargetForSelector方法的返回值是nil,跳转loc_116064流程

Xnip2021-07-11_23-12-20.jpg

此时进入了慢速转发流程

  • 如果methodSignatureForSelector没有实现直接跳转到loc_1163e3流程
  • 如果methodSignatureForSelector返回值等于nil跳转到loc_11645e流程
  • 如果methodSignatureForSelector返回了签名信息的对象

Xnip2021-07-11_23-14-54.jpg

  • loc_1163e3流程:直接报错跳转到loc_116457流程
  • loc_116457流程:doesNotRecognizeSelector崩溃处理

Xnip2021-07-11_23-15-55.jpg

  • loc_11645e流程:doesNotRecognizeSelector崩溃处理

Xnip2021-07-11_23-20-59.jpg

返回签名信息forwardInvocation方法处理事务