消息在OC中方法調用是一個消息發(fā)送的過程。OC方法最終被生成為C函數(shù),并帶有一些額外的參數(shù)(self 、_cmd)
objc_msgSend(void /* id self, SEL op, ... */ )
OC的方法本質
- 在編譯時你寫的 OC 函數(shù)調用的語法都會被翻譯成一個 C 的函數(shù)調用 objc_msgSend()
[array insertObject:obj atIndex:5];
//等價于
objc_msgSend(array, @selector(insertObject:atIndex:), obj, 5);
OC消息轉發(fā)的步驟
1.通過 的
指針 找到
的
;
2.在 的
(方法緩存) 的散列表中尋找對應的
(方法實現(xiàn));
3.如果在(方法緩存) 中沒有找到對應的
(方法實現(xiàn)) 的話,就繼續(xù)在
的
(方法列表) 中找對應的
,如果找到,填充到
(方法緩存) 中,并返回
;
4.如果在 中沒有找到這個
,就繼續(xù)在它的
(父類)中尋找;
5.一旦找到對應的 ,直接執(zhí)行
對應
方法實現(xiàn)的
(方法實現(xiàn))。
6.若找不到對應的 ,要開始進入
,消息被轉發(fā)或者臨時向
添加這個
對應的實現(xiàn)方法,否則就會發(fā)生崩潰。
+ (BOOL)resolveInstanceMethod:(SEL)sel;
+ (BOOL)resolveClassMethod:(SEL)sel;
- (id)forwardingTargetForSelector:(SEL)aSelector;
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
- (void)forwardInvocation:(NSInvocation *)anInvocation;
-
動態(tài)方法解析和消息轉發(fā)流程:
圖片來自網絡
OC 中給一個對象發(fā)送消息的完整步驟:
1.在對象類的 dispatch_table 中嘗試找到該消息。如果找到了,跳到相應的函數(shù)IMP去執(zhí)行實現(xiàn)代碼(參考OC消息轉發(fā)的步驟);
2.如果沒有找到,運行時系統(tǒng)會發(fā)送+resolveInstanceMethod:或者 +resolveClassMethod:嘗試去 resolve 這個消息;
3.如果 resolve 方法返回NO,運行時系統(tǒng)就發(fā)送 -forwardingTargetForSelector: 允許你把這個消息轉發(fā)給另一個對象;(resolve 方法返回YES時,運行時系統(tǒng)就會重新啟動一次消息發(fā)送的過程)
4.如果沒有新的目標對象返回,運行時系統(tǒng)就會調用 -methodSignatureForSelector:和-forwardInvocation: 消息。你可以發(fā)送-invokeWithTarget:消息來手動轉發(fā)消息或者發(fā)送 -doesNotRecognizeSelector:拋出異常;
5.如果都沒有,系統(tǒng)拋出異常。
類方法的調用過程 和對象方法調用差不多,流程如下:
1.通過類對象指針 找到所屬的
(元類);
2.在 (元類) 的
(方法列表) 中找到對應的
;
執(zhí)行對應的 。
注意
需要注意的是類方法的解析,動態(tài)增加方法時候,需要加到元類上,因為類方法列表是在元類對象中存儲的。