iOS-底层原理11-动态方法决议走两次和消息转发不能为self

《iOS底层原理文章汇总》

上一篇文章中iOS-底层原理10-动态方法决议&消息转发探索了动态方法决议和消息转发,有两个问题还需要探索

问题一:动态方法决议+ (BOOL)resolveInstanceMethod:(SEL)sel里面,没有对sel方法say666进行重新指定imp,则此动态决议方法+ (BOOL)resolveInstanceMethod:(SEL)sel会走两次,为什么会走两次呢???

resloveInstanceMethod两次@2x.png

28.gif
  • 第一次动态方法决议后,方法返回,是什么时候进入第二次动态方法决议方法的呢???通过打印第二进入前的堆栈情况,获取堆栈信息如下,得到第二次触发是在CoreFoundation`-[NSObject(NSObject) methodSignatureForSelector:],后面探索实质为消息的慢速转发流程。
第二次动态方法决议进入堆栈@2x.png
  • 通过hopper反汇编查看消息转发流程: ___forwarding_prep_0___->____forwarding___->forwardingTargetForSelector:->methodSignatureForSelector:查看methodSignatureForSelector:源码实现,进入___methodDescriptionForSelector->class_getInstanceMethod从而在class_getInstanceMethod方法中打断点调试下。
methodSignatureForSelector源码@2x.png
methodDescriptionForSelector源码.png

class_getInstanceMethod断点调试,进入到消息的慢速查找流程lookUpImpOrForward(nil, sel, cls, LOOKUP_RESOLVER)

class_getInstanceMethod@2x.png
第二次动态方法决议.png
第二次进入resolveInstanceMethod方法.png
  • 第二次动态方法决议还没找到imp,程序报错_objc_msgForward_impcache
29.gif
第二次动态方法决议没找到imp报错@2x.png

问题二:消息的快速转发流程中,在forwardingTargetForSelector:方法中动态添加本类的sayHello的Imp,结果程序崩溃,为什么呢???

新建LGStudent的类,将消息转发给LGStudent的对象,并不会报错,能正常执行

快速转发通过runtime添加Imp@2x.png
消息快速转发本类对象self@2x.png
  • 转发给LGStudent对象新加的方法程序能正常转发,通过反编译代码,查看反编译的- (id)forwardingTargetForSelector:(SEL)aSelector源码
快速转发给非本类对象@2x.png
rax=rbxforwardingTargetForSelector返回self.png
  • return self,则rax == rbx,进入loc_64a67,发现if (strncmp(r13, "_NSZombie_", 0xa) == 0x0) goto loc_64dc1;,进入goto loc_64dd7
loc_64dc1.png
returnself奔溃报错.png
消息转发给本类对象程序崩溃@2x.png

推荐阅读更多精彩内容