一、消息轉(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