上一篇文章中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