Runtime 消息转发

目录

  1. 消息转发背景知识
  2. 消息转发使用方式
  3. 消息转发常见问题

消息转发背景知识

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

你可能感兴趣的:(Runtime 消息转发)