007转发解析详情

161 阅读2分钟

- 调用方法的流程:

  • 1、从cache缓存查找
  • 2、缓存没有,则从对象方法列表或者父类的方法列表去查找
  • 3、方法列表没找到,则进行消息解析

imp = forwardImp

for(){
if (slowpath((curClass = curClass->getSuperclass()) == nil)) {
 // No implementation found, and method resolver didn't help.
// Use forwarding.
imp = forward_imp;
break; //跳出循环
}
}
//进入方法解析
// No implementation found. Try method resolver once.
    if (slowpath(behavior & LOOKUP_RESOLVER)) {
        behavior ^= LOOKUP_RESOLVER;
        return resolveMethod_locked(inst, sel, cls, behavior);
    }          

进入方法的解析 resolveMethod_locked

  • resolveInstanceMethod

  • resolveClassMethod,

  • 如果没有进行方法重新解析则会报错,没找到方法

方法名SEL没有找到IMP则会报错

实例方法没实现,调用 resolveInstanceMethod

  • 则添加实例方法的实现
  • 运行时,动态给对象添加方法
  • 添加的方法会缓存的对象的方法列表中 image.png

image.png

类方法没实现,调用resolveClassMethod

  • 添加类方法
  • 如果没找到方法实现,则会再次调用resolveInstanceMethod
  • 查看有没有实例方法实现
  • 类方法最终也会缓存到对象的方法列表

image.png

image.png

- 注意: class_getMethodImplementation(类对象, 方法);

  • 1、类对象 对应的是实例方法,没有实例方法(方法找不到)会死循环
  • 2、类对象 如果对应的是类方法(应该是实例方法)找不到也会死循环

+(BOOL)resolveInstanceMethod:(SEL)sel {     NSLog(@"%s",func);     IMP imp = class_getMethodImplementation(self.class, @selector(addInstanceMethod3));

    class_addMethod(self.class, sel, imp, "v@:");     return [super resolveInstanceMethod:sel]; }

- 注意:IMP imp = class_getMethodImplementation(类对象, 实例方法));

  • IMP imp = class_getMethodImplementation(元类, 类方法));
  • 1、类对象对应的实例方法没实现,则进入 resolveInstanceMethod
  • 2、如果是元类 和实例方法也是方法找不到死循环 +(BOOL)resolveClassMethod:(SEL)sel {     NSLog(@"%s",func);

    IMP imp = class_getMethodImplementation(self.class, @selector(addClassMethod));

    class_addMethod(objc_getMetaClass("Person"), sel, imp, "v@:");

    return [super resolveClassMethod:sel]; }

如果找到方法则缓存方法,返回方法实现

  • 方法缓存到当前对象的方法列表里 image.png

消息决议没有动态添加方法实现,接下来消息转发

消息快速转发

  • -(id)forwardingTargetForSelector:(SEL)aSelector {
  • 返回能响应消息的对象
  • }
  • 快速转发没处理,还会进入慢速转发

慢速转发

  • 1、-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{}
  • 2、-(void)forwardInvocation:(NSInvocation *)anInvocation{}
  • 两个方法配合实现消息慢速转发
  • 给消息添加一个响应的选择器来响应消息指行 invokeWithTarget:

-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {

    NSLog(@"%s-%@",func,NSStringFromSelector(aSelector));

    return [NSMethodSignature signatureWithObjCTypes:"v@:"];

}

-(void)forwardInvocation:(NSInvocation *)anInvocation {

    Teacher *t = [Teacher alloc];

    if ([self respondsToSelector:anInvocation.selector]) {

        [anInvocation invokeWithTarget:self];

    }else if ([t respondsToSelector:anInvocation.selector] ) {

        [anInvocation invokeWithTarget:t];

    }else {

        NSLog(@"%s-%@",func,NSStringFromSelector(anInvocation.selector));     } }

查找消息查找流程的代码

其中消息转发的日志文件中显示了消息的快速转发和慢速转发

image.png

至此,如果还没有相应方法则提示方法未实现或者报错没找到方法

消息传递的过程中的三次机会分别是

  • 1、消息决议,动态添加方法
  • 2、快速转发,找到响应方法的对象,执行消息
  • 3、慢速转发:找到能够响应方法的选择器,执行消息