Runtime之消息發(fā)送和消息轉(zhuǎn)發(fā)

簡(jiǎn)介:

[object doSomething];
編譯器會(huì)轉(zhuǎn)換為下面形式:
objc_msgSend(receiver, selector);

如果消息含有參數(shù),則為:

objc_msgSend(receiver, selector, arg1, arg2, ...)

1、消息發(fā)送機(jī)制

  • 檢查selector 是否需要忽略(比如 Mac OS X 開(kāi)發(fā)萍桌,有了垃圾回收就不理會(huì) retain,release 這些函數(shù)凌简。)
  • 檢查target是否為nil上炎,如果為nil,直接cleanup雏搂,然后return(這就是為什么可以向nil發(fā)送消息的原因)
  • 然后在target的Class中根據(jù)Selector去找IMP反症。

尋找IMP的過(guò)程:

  • 先從當(dāng)前class的cache方法列表(cache methodLists)里去找。
  • 如果找到了畔派,跳到對(duì)應(yīng)函數(shù)實(shí)現(xiàn)。
  • 如果沒(méi)找到润绵,就從class的方法列表(methodLists)里找线椰。
  • 如果還找不到,就到super class的方法列表里找尘盼,直到找到基類(lèi)(NSObject)為止憨愉。
  • 最后再找不到,就會(huì)進(jìn)入動(dòng)態(tài)方法解析和消息轉(zhuǎn)發(fā)的機(jī)制卿捎。

2配紫、消息轉(zhuǎn)發(fā)機(jī)制

  • 消息發(fā)送是Runtime通過(guò)selector快速查找IMP的過(guò)程,有了函數(shù)指針就可以執(zhí)行對(duì)應(yīng)的方法實(shí)現(xiàn)午阵;
  • 消息轉(zhuǎn)發(fā)是在查找IMP失敗后執(zhí)行一系列轉(zhuǎn)發(fā)流程的慢速通道躺孝,如果不作轉(zhuǎn)發(fā)處理享扔,則會(huì)打日志和拋出異常。

①動(dòng)態(tài)方法解析:

對(duì)象在收到無(wú)法解讀的消息之后植袍,首先將調(diào)用所屬類(lèi)的下列類(lèi)方法:

+(BOOL)resolveInstanceMethod:(SEL)name

demo解析:

#import <Foundation/Foundation.h>@interface Person : NSObject
- (void)eat; //沒(méi)有實(shí)現(xiàn)
@end

運(yùn)行結(jié)果
image-20180418170832412.png

在person.m中寫(xiě)入以下代碼惧眠,對(duì)象在接受的無(wú)法解讀的消息后,首先會(huì)調(diào)用+(BOOL)resolveInstanceMethod:(SEL)sel或者+ (BOOL)resolveClassMethod:(SEL)sel, 詢(xún)問(wèn)是否有動(dòng)態(tài)添加方法來(lái)進(jìn)行處理于个,處理實(shí)例如下

@implementation Person
+(BOOL)resolveInstanceMethod:(SEL)sel
{
    NSLog(@"sel = %@",NSStringFromSelector(sel));
    return [super resolveInstanceMethod:sel];
}

結(jié)果如下:
image-20180418172155127.png

具體添加方法如下:

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    if (sel == @selector(eat))
    {
        class_addMethod([self class], sel, (IMP)addeat, "V@");
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}
void addeat(id self,SEL sel,NSString *str) 
{
    NSLog(@"添加成功");
}

class_addMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp, const char * _Nullable types)
    參數(shù)一:被添加方法的累
    參數(shù)二:要添加的方法
    參數(shù)三:實(shí)現(xiàn)這個(gè)方法的函數(shù)
    參數(shù)四:定義返回值和參數(shù)類(lèi)型的字符串(i:代表int  v代表void @:代表參數(shù))

如果動(dòng)態(tài)添加失敗氛魁,就會(huì)進(jìn)入下面的操作

②消息轉(zhuǎn)發(fā)重定向

- (id)forwardingTargetForSelector:(SEL)aSelector

在消息轉(zhuǎn)發(fā)機(jī)制執(zhí)行前,Runtime系統(tǒng)會(huì)再給我們一次偷梁換柱的機(jī)會(huì)厅篓,即通過(guò)重載- (id)forwardingTargetForSelector:(SEL)aSelector方法替換消息的接受者為其他對(duì)象:

新建一個(gè)tempObject秀存,定義eat方法,在.m文件中實(shí)現(xiàn)

#import "tempObject.h"

@implementation tempObject
- (void)eat
{
    NSLog(@"i am tempObject");
}
@end

在person類(lèi)中將接受消息對(duì)象換為tempObject

-(id)forwardingTargetForSelector:(SEL)aSelector
{
    return [[tempObject alloc]init];
}

結(jié)果如下:


image-20180419150039116.png

③ 消息轉(zhuǎn)發(fā)

首先獲取方法的簽名羽氮,拿著簽名再去配發(fā)消息或链,如果不能接受消息就會(huì)拋出異常

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
- (void)forwardInvocation:(NSInvocation *)anInvocation;

獲取方法簽名

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector OBJC_SWIFT_UNAVAILABLE("")
{
    //轉(zhuǎn)化字符
    NSString *sel = NSStringFromSelector(aSelector);
    //判斷, 手動(dòng)生成簽名
    if([sel isEqualToString:@"eat"])
    {
        return [NSMethodSignature signatureWithObjCTypes:"v@:"];
    }
    else
    {
        return [super methodSignatureForSelector:aSelector];
    }
}

拿到方法簽名配發(fā)消息

- (void)forwardInvocation:(NSInvocation *)anInvocation OBJC_SWIFT_UNAVAILABLE(""){
    NSLog(@"forwardInvocation: %@", NSStringFromSelector([anInvocation selector]));
    //取到消息
    SEL seletor = [anInvocation selector];
    //轉(zhuǎn)發(fā)
    tempObject *temp = [[tempObject alloc]init];
    if([temp respondsToSelector:seletor])
    {
        //調(diào)用對(duì)象,進(jìn)行轉(zhuǎn)發(fā)
        [anInvocation invokeWithTarget:temp];
    }
    else
    {
        return [super forwardInvocation:anInvocation];
    }
}

如果不能接受消息,拋出異常

- (void)doesNotRecognizeSelector:(SEL)aSelector
{
    NSString *selStr = NSStringFromSelector(aSelector);
    NSLog(@"%@不存在",selStr);
}

參考文章:

runtime 消息轉(zhuǎn)發(fā):http://www.reibang.com/p/8cd06cd496d5
? runtime消息轉(zhuǎn)發(fā)demo:http://www.2bjs.com/%E6%9E%B6%E6%9E%84/iOS%20%E6%B6%88%E6%81%AF%E8%BD%AC%E5%8F%91%E6%9C%BA%E5%88%B6Demo%E8%A7%A3%E6%9E%90/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市乏苦,隨后出現(xiàn)的幾起案子株扛,更是在濱河造成了極大的恐慌,老刑警劉巖汇荐,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件洞就,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡掀淘,警方通過(guò)查閱死者的電腦和手機(jī)旬蟋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)革娄,“玉大人倾贰,你說(shuō)我怎么就攤上這事±雇铮” “怎么了匆浙?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)厕妖。 經(jīng)常有香客問(wèn)我首尼,道長(zhǎng),這世上最難降的妖魔是什么言秸? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任软能,我火速辦了婚禮,結(jié)果婚禮上举畸,老公的妹妹穿的比我還像新娘查排。我一直安慰自己,他們只是感情好抄沮,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布跋核。 她就那樣靜靜地躺著岖瑰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪了罪。 梳的紋絲不亂的頭發(fā)上锭环,一...
    開(kāi)封第一講書(shū)人閱讀 51,590評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音泊藕,去河邊找鬼辅辩。 笑死,一個(gè)胖子當(dāng)著我的面吹牛娃圆,可吹牛的內(nèi)容都是我干的玫锋。 我是一名探鬼主播,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼讼呢,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼撩鹿!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起悦屏,我...
    開(kāi)封第一講書(shū)人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤节沦,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后础爬,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體甫贯,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年看蚜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了叫搁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡供炎,死狀恐怖渴逻,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情音诫,我是刑警寧澤惨奕,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站竭钝,受9級(jí)特大地震影響墓贿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蜓氨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望队伟。 院中可真熱鬧穴吹,春花似錦、人聲如沸嗜侮。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至顷霹,卻和暖如春咪惠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背淋淀。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工遥昧, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人朵纷。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓炭臭,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親袍辞。 傳聞我的和親對(duì)象是個(gè)殘疾皇子鞋仍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,715評(píng)論 0 9
  • 消息發(fā)送和轉(zhuǎn)發(fā)流程可以概括為:消息發(fā)送(Messaging)是 Runtime 通過(guò) selector 快速查找 ...
    lylaut閱讀 1,844評(píng)論 2 3
  • 我們常常會(huì)聽(tīng)說(shuō) Objective-C 是一門(mén)動(dòng)態(tài)語(yǔ)言搅吁,那么這個(gè)「動(dòng)態(tài)」表現(xiàn)在哪呢威创?我想最主要的表現(xiàn)就是 Obje...
    Ethan_Struggle閱讀 2,195評(píng)論 0 7
  • 來(lái)源‖法律教育網(wǎng) 在民間借貸糾紛中肚豺,借條是十分重要的證據(jù)之一,對(duì)明確雙方當(dāng)事人借貸關(guān)系成立與否具有重要意義党瓮,然而在...
    小好閱讀 471評(píng)論 1 2