OC中的方法調(diào)用,其實都是轉(zhuǎn)化為objc_msgSend函數(shù)的調(diào)用,objc_mesgSend的執(zhí)行流程可分為3個階段
- 消息發(fā)送
- 動態(tài)方法解析
- 消息轉(zhuǎn)發(fā)
消息轉(zhuǎn)發(fā)

動態(tài)方法解析

開發(fā)者可以實現(xiàn)以下的辦法來實現(xiàn)動態(tài)添加方法實現(xiàn)
- +resolveInstanceMethod:
- +resolveClassMethod:
動態(tài)解析后會重新走消息發(fā)送的流程,從receiveClass的cache中查找方法這一步開始執(zhí)行
創(chuàng)建一個Person類,然后在.h文件中寫一個- (void)test,但是不寫具體實現(xiàn),然后調(diào)用.會打印出最常見的unrecognized selector sent to instance.
- (void)other{
NSLog(@"%s",__func__);
}
+ (BOOL)resolveInstanceMethod:(SEL)sel{
if (sel == @selector(test)) {
//獲取其他方法
Method method = class_getInstanceMethod(self, @selector(other));
//動態(tài)添加test的方法
class_addMethod(self, sel, method_getImplementation(method), method_getTypeEncoding(method));
return YES;
}
return [super resolveInstanceMethod:sel];
}
消息轉(zhuǎn)發(fā)
如果一個方法在消息發(fā)送階段沒有找到相關(guān)方法,也沒有進行動態(tài)方法解析,這個時候就會走到消息轉(zhuǎn)發(fā)階段了.

forwardingTargetForSelector
創(chuàng)建兩個類Person和Student,在Person.h里面寫一個實例方法,但是不去實現(xiàn)相關(guān)方法。
在Person里面實現(xiàn)這個方法
- (id)forwardingTargetForSelector:(SEL)aSelector {
if (aSelector == @selector(test)) {
return [[Student alloc]init];
}
return nil;
}
調(diào)用forwardingTargetForSelector,返回值不為nil時,會調(diào)用objc_msgSend(返回值, SEL),結(jié)果就是調(diào)用了objc_msgSend(Student,test)
methodSignatureForSelector(方法簽名)
當forwardingTargetForSelector返回值為nil,或者都沒有調(diào)用該方法的時候,系統(tǒng)會調(diào)用methodSignatureForSelector方法。調(diào)用methodSignatureForSelector,返回值不為nil,調(diào)用forwardInvocation:方法;返回值為nil時,調(diào)用doesNotRecognizeSelector:方法
對于方法簽名的生成方式
- [NSMethodSignature signatureWithObjCTypes:"i@:i"]
- [[[Student alloc]init] methodSignatureForSelector:aSelector];
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
if (aSelector == @selector(test)) {
return [[[Student alloc]init]methodSignatureForSelector:aSelector];
// return [NSMethodSignature signatureWithObjCTypes:"i@:i"];
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
NSLog(@"=======");
}
NSInvocation中封裝了一個方法調(diào)用,包括方法調(diào)用者,方法名,方法參數(shù).
- anInvocation.target 方法調(diào)用者
- anInvocation.selector 方法名
- [anInvocation getArgument:NULL atIndex:0]