目錄
消息轉(zhuǎn)發(fā)背景知識
1.消息轉(zhuǎn)發(fā)的定義
Objective-C的方法調(diào)用基于消息轉(zhuǎn)發(fā)機制
編譯器將如下代碼
[alen normalRun]
編譯成消息傳遞方法割疾,即objc_msgSend 汽纠。需要傳入接收者以及方法名
((NSString * (*)(id, SEL))(void *) objc_msgSend)((id)alen, @selector(normalRun))
消息轉(zhuǎn)發(fā)使用方式
如果方法沒有實現(xiàn)瑟枫,則調(diào)用的時候會產(chǎn)生三次攔截
1.第一次攔截 resolveInstanceMethod
如果沒有實現(xiàn)方法則首先會被 resolveInstanceMethod 方法攔截好港,此時可以通過 runtime 的 addMethod 來加入方法并進行調(diào)用。
+ (BOOL)resolveInstanceMethod:(SEL)sel {
if (sel == @selector(run)) {
//兩種替換的方法
//方法1:使用C語言方法
// class_addMethod(self, sel, (IMP)run, "v@:");
//方法2:使用OC方法
class_addMethod(self, sel, class_getMethodImplementation([Person class], @selector(fakeRun)), "v@:");
return YES;
}
return [super resolveInstanceMethod:sel];
}
2.第二次攔截 forwardingTargetForSelector
第二次攔截可將方法轉(zhuǎn)發(fā)到已經(jīng)實現(xiàn)方法的實體類中
- (id)forwardingTargetForSelector:(SEL)aSelector {
return self;
}
3.第三次攔截 methodSignatureForSelector
通過 methodSignatureForSelector 將方法轉(zhuǎn)發(fā)到想要的實體類中琴拧,在對應實體類中
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
NSMethodSignature *signature = [jeep methodSignatureForSelector:aSelector];
return signature;
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
SEL selector = [anInvocation selector];
if ([jeep methodSignatureForSelector:selector]) {
[anInvocation invokeWithTarget:jeep];
} else {
[super forwardInvocation:anInvocation];
}
}
消息轉(zhuǎn)發(fā)常見問題
1.class_copyMethodList 獲取不到未實現(xiàn)的方法
2.category 覆蓋類的方法
是在類的 MethodList 中添加 selector ,IMP 為 category 的名稱
//通過category添加的方法
(iOSInterviewProblems`-[Person(MethodRun) normalRun] at Person+MethodRun.m:17)
//類添加的方法
(iOSInterviewProblems`-[Person normalRun] at Person.m:40)
示例參見 github Demo