oc消息轉(zhuǎn)發(fā)機(jī)制

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

在OC中,調(diào)用一個(gè)對(duì)象的方法,實(shí)際上是給對(duì)象發(fā)了一條消息,在編譯Objective-C函數(shù)調(diào)用的語法時(shí),會(huì)被翻譯成一個(gè)C的函數(shù)調(diào)用:objc_msgSend(),例如:

[array insertObject:foo atIndex:2];

//會(huì)被翻譯成:

objc_msgSend(array, @selector(insertObject:atIndex), foo, 2);

以[object foo]為例:

通過object的isa指針找到它的class

在class的method_list中找到foo

如果class中沒找到foo,則繼續(xù)往他的superclass中查找

一旦找到foo這個(gè)函數(shù),就去執(zhí)行對(duì)應(yīng)的方法實(shí)現(xiàn)(IMP)

如果一直沒有找到foo,OC的runtime將繼續(xù)下面的步驟:

二、動(dòng)態(tài)方法決議與消息轉(zhuǎn)發(fā)

在oc中,如果向一個(gè)對(duì)象發(fā)送一條該對(duì)象無法處理的消息(對(duì)應(yīng)selector不存在),會(huì)導(dǎo)致程序crash, 但是,在crash之前,oc的運(yùn)行時(shí)系統(tǒng)會(huì)先經(jīng)過以下兩個(gè)步驟:

Dynamic Method Resolution(動(dòng)態(tài)方法決議)

Message Forwarding(消息轉(zhuǎn)發(fā))

Dynamic Method Resolution(動(dòng)態(tài)方法決議)

讓我們可以在程序運(yùn)行時(shí)動(dòng)態(tài)的為一個(gè)selector提供實(shí)現(xiàn),如果我們添加了函數(shù)的實(shí)現(xiàn),并返回YES,運(yùn)行時(shí)系統(tǒng)會(huì)重啟一次消息的發(fā)送過程,調(diào)用動(dòng)態(tài)添加的方法

調(diào)用實(shí)例方法:- (BOOL)resolveInstanceMethod:(SEL)sel

調(diào)用類方法:+? (BOOL)resolveClassMethod:(SEL)sel

+ (BOOL)resolveInstanceMethod:(SEL)sel{

?? if (sel == @selector(foo)) {

? ? ?? class_addMethod([self class], sel, (IMP)dynamicMethodIMP, "V@:");

? ? ?? return YES;

?? }

?? return [super resolveInstanceMethod:sel];

}

void dynamicMethodIMP(id self, SEL _cmd){

?? NSLog(@"%s", __PRETTY_FUNCTION__);

}

class_addMethod(Class cls, SEL name, IMP imp, const char *types)? ===>? 動(dòng)態(tài)添加方法

const char *types:

”v@:”這是一個(gè)void類型的方法,沒有參數(shù)傳入

“i@:”這是一個(gè)int類型的方法,沒有參數(shù)傳入。

”i@:@”這是一個(gè)int類型的方法,有一個(gè)參數(shù)傳入。==> ''i@:*''

如果方法返回NO時(shí),將會(huì)進(jìn)入下一步:

Message Forwarding? (消息轉(zhuǎn)發(fā))

先通? SEL查找:先調(diào)用:- (id)forwardingTargetForSelector:(SEL)aSelector ,通過aSelector進(jìn)行查找方法名,返回對(duì)象。

### ProxyDispatcher.h

?

@interface ProxyDispatcher : NSObject

- (void)Func;

@end

?

### ProxyDispatcher.m

?

- (id)forwardingTargetForSelector:(SEL)aSelector{

?

?? if (aSelector == @selector(Func)) {

? ? ?? return [DispatcherObject new];

?? }


?? return nil;

}

?

### DispatcherObject.m

?

- (void)Func{

?? NSLog(@"%s", __PRETTY_FUNCTION__);

}

后通過? 簽名查找: -? (NSMethodSignature )methodSignatureForSelector:(SEL)aSelector *SEL查找失敗(返回nil或self)

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{

?? NSMethodSignature *methodSignature = [super methodSignatureForSelector:aSelector];

? ? ?? if (!methodSignature) {

? ? ?? methodSignature = [NSMethodSignature signatureWithObjCTypes:"v@:*"];

?? }

?? return methodSignature;

}

消息轉(zhuǎn)發(fā)流程圖:


參考引用:http://www.cocoachina.com/ios/20151208/14595.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容