前言:
我们开发过程中调用方法,有时会遇到这样的错误
因为该反复为实现导致的崩溃,那么从上篇文章中我们得到了一个这样的结论,当方法imp
未找到时lookUpImpOrForwrd
会返回
那么这篇文章就着重分析下resolveMethod_locked
的作用.
resolveMethod_locked源码分析
流程如下:
resolveInstanceMethod 实例方法决议
上个流程图可以看出当前类非元类的时候走的是resolveInstanceMethod
方法决议,进入
实例方法决议
resolveInstanceMethod源码分析
因为say666
是实例方法,通过上图的源码分析,苹果爸爸又执行lookUpImpOrNil
方法,即通过lookUpImpOrNil
方法又会进入lookUpImpOrForward
慢速查找流程找resolveInstanceMethod
方法如果未找到
返回,找到返回imp
所以,针对实例方法say666
未实现的报错崩溃,可以通过在类
中重写resolveInstanceMethod
类方法,并将其指向其他方法的实现
为什么会打印两次,查看堆栈信息具体分钟,在控制台输入bt
继续断点跟进
通过两次的打印流程,为什么会走CoreFoundation
__methodDescriptionForSelector‘`后才进行方法决议?
类方法决议
通过堆栈信息可以看出类方法决议的过程也是两次的调用?
从上图的流程看,在崩溃之前均需要走**resolveInstanceMethod
是否意味着可以在此位置修复崩溃级bug,答案是当然可以,根据代码和isa走位图分析,实例方法
的resolveInstanceMethod
** 方法走的是**类 -- 父类 -- 根类 -- nil流程
最终调用的是NSObject
的****resolveInstanceMethod
方法,类方法resolveClassMethod
走的是元类 -- 根元类 -- 根类 -- nil
流程.最终也是调用NSObject``的resolveInstanceMethod
方法,那么就可以复写NSObject的resolveInstanceMethod的方法实现崩溃拦截
,**添加NSObject添加分类
重写resolveInstanceMethod
方法具体如下:
消息转发流程
上一个小结分析了消息在为查找到imp的状态下进行了方法的决议,那么在程序崩溃之前是否还有其他的方法可以调用,继续lookUpImpOrForward
断点跟进
根据代码流程获取日志
在main
函数中实现instrumentObjcMessageSends
方法,在tmp
中获取日志,具体如下:
再访达中前往文件地址查看msgSends
文件
有此文件可以看出在崩溃之前我们可以
-
两次
动态方法决议
:resolveInstanceMethod
方法 -
两次
消息快速转发
:forwardingTargetForSelector
方法 -
两次
消息慢速转发
:methodSignatureForSelector
+resolveInstanceMethod
由此可见,苹果爸爸在给我们崩溃的时候提供了三次挽救崩溃的机会,那么我们就会得出一张经典的消息转发流程图,如下:
forwardingTargetForSelector
在源码中未开放此方法的实现,只能通过汇编反编译
去了解,也可以通过api文档
去了解
如果返回nil,可以通过消息的慢速转发流程处理,具体如下:
methodSignatureForSelector/forwardInvocation
具体文档如下:
最后的崩溃
如果你没有实现第三步那么程序就真的要走崩溃流程了
- doesNotRecognizeSelector:
然后闪退。
以上就是消息的转发流程,在文章中有个问题没有解决,就是为什么会有两次的方法调用...具体的原因待下次分析.