簡單描述就是:
消息轉(zhuǎn)發(fā)就是實例對象或者類調(diào)用了方法后宠进,都會轉(zhuǎn)化成objc_msgSend的方式晕拆,給方法調(diào)用者發(fā)送了一條selector消息,通過isa查找類或父類的方法列表材蹬,如褁沒有找到對應(yīng)的方法实幕,則通過動態(tài)方法解析和消息轉(zhuǎn)發(fā)來補救,還不行則會crash堤器。
objc_msgSend具體還包含三個步驟:
1.消息發(fā)送:
在當前類或父類中查找方法茬缩,找到則存儲他的imp(指向方法實現(xiàn)的指針);
2.動態(tài)方法解析:
如褁消息發(fā)送沒有找到對應(yīng)方法吼旧,則動態(tài)方法解析器開始工作凰锡,先判斷當前cls對象是不是元類,也就是如果是對象方法會走到_class_resolveInstanceMethod,如過是類對象則會執(zhí)行_class_resolveClassMethod,如過到最后沒有查到圈暗,NSObject的resolveInstanceMethod會返回NO掂为。
#pragma mark - 動態(tài)方法解析
#比如有個run 方法沒有聲明和實現(xiàn),增加方法后就不會出現(xiàn)找不到方法崩潰的問題了员串。
+ (BOOL)resolveInstanceMethod:(SEL)sel {
NSLog(@"動態(tài)方法解析 - %@",self);
if (sel == @selector(run)) {
// 我們動態(tài)解析對象方法
NSLog(@"對象方法 run 解析走這里");
SEL readSEL = @selector(readBook);
Method readM= class_getInstanceMethod(self, readSEL);
IMP readImp = method_getImplementation(readM);
const char *type = method_getTypeEncoding(readM);
return class_addMethod(self, sel, readImp, type);
}
return [super resolveInstanceMethod:sel];
#此時只是給對象方法添加了一個imp勇哗,接下來再次進入查找imp流程,重復(fù)之前的操作寸齐,只不過現(xiàn)在對象方法已經(jīng)有了imp欲诺,就會返回imp后繼續(xù)執(zhí)行
3.消息轉(zhuǎn)發(fā)抄谐;
消息轉(zhuǎn)發(fā)就是對方法進行替換了,具體可以看看http://www.reibang.com/p/4f211020de05
扰法,說明挺詳細蛹含,能實現(xiàn)一些黑魔法的方式,比如里面提到的message的.m來實現(xiàn)VC的方法塞颁,這樣可以提供.M給用戶浦箱,但是重點方法保護起來。
補充一點:runtime如何通過selector找到對應(yīng)的IMP地址祠锣?
每一個類對象中都一個對象方法列表(對象方法緩存)
類方法列表是存放在類對象中isa指針指向的元類對象中(類方法緩存)酷窥。
方法列表中每個方法結(jié)構(gòu)體中記錄著方法的名稱,方法實現(xiàn),以及參數(shù)類型,其實selector本質(zhì)就是方法名稱,通過這個方法名稱就可以在方法列表中找到對應(yīng)的方法實現(xiàn)伴网。
當我們發(fā)送一個消息給一個NSObject對象時蓬推,這條消息會在對象的類對象方法列表里查找。
當我們發(fā)送一個消息給一個類時澡腾,這條消息會在類的Meta Class對象的方法列表里查找沸伏。