目录
消息转发背景知识
1.消息转发的定义
Objective-C的方法调用基于消息转发机制
编译器将如下代码
[alen normalRun]
编译成消息传递方法,即objc_msgSend 。需要传入接收者以及方法名
((NSString * (*)(id, SEL))(void *) objc_msgSend)((id)alen, @selector(normalRun))
消息转发使用方式
如果方法没有实现,则调用的时候会产生三次拦截
1.第一次拦截 resolveInstanceMethod
如果没有实现方法则首先会被 resolveInstanceMethod 方法拦截,此时可以通过 runtime 的 addMethod 来加入方法并进行调用。
+ (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
第二次拦截可将方法转发到已经实现方法的实体类中
- (id)forwardingTargetForSelector:(SEL)aSelector {
return self;
}
3.第三次拦截 methodSignatureForSelector
通过 methodSignatureForSelector 将方法转发到想要的实体类中,在对应实体类中
- (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];
}
}
消息转发常见问题
1.class_copyMethodList 获取不到未实现的方法
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
网友评论