消息转发流程

实例方法的流程

RunTime
  • 对象实例收到消息(SEL+参数)
  • 根据存储在对象实例中的ISA到类对象,类对象依次查找Class Cache(方法表缓存)和dispatch table找到对应的Method,如果找到Method,执行对应Method的IMP(方法体),并且返回结果
  • 如果找不到Method,则根据类对象中的super_class指针找到父类的Class对象。一直找到NSObject的类对象
  • 如果NSObject也无法找到这个SEL,则进入消息转发机制
  • 如果消息转发机制无法处理,则抛出异常: doesNotRecognizeSelector

一个方法的调用实际上就是SEL(方法名)通过Runtime找到IMP(方法执行体)

消息转发机制

在Objective C的方法调用过程中,我们提到了当无法响应一个selector时,在抛出异常之前会先进入消息转发机制。
在触发消息转发机制即forwardInvocation:之前,Runtime提供了两步来进行轻量级的动态处理这个selector.

  • resolveInstanceMethod:
这个方法提供了一个机会:为当前类无法识别的SEL动态增加IMP。
比如:最常见的可以通过class_addMethod

void dynamicMethodIMP(id self, SEL _cmd){/*...implementation...*/}

+ (BOOL) resolveInstanceMethod:(SEL)aSEL
{
    if (aSEL == @selector(resolveThisMethodDynamically))
    {
          class_addMethod([self class], aSEL, (IMP) dynamicMethodIMP, "v@:");
          return YES;
    }
    return [super resolveInstanceMethod:aSel];
}

Tips,这里的"v@:"表示方法参数编码,v表示Void,@表示OC对象,:表示SEL类型。

如果resolveInstanceMethod返回NO,则表示无法在这一步动态的添加方法,则进入下一步:


  • forwardingTargetForSelector:
这个方法提供了一个机会:简单的把这个SEL交给另外一个对象来执行。

-(id)forwardingTargetForSelector:(SEL)aSelector{
    if (aSelector == @selector(dynamicSelector) && [self.myObj respondsToSelector:@selector(dynamicSelector)]) {
        return self.myObj;
    }else{
        return [super forwardingTargetForSelector:aSelector];
    }
}

如果上述两步都无法完成这个SEL的处理,则进入消息转发机制

消息转发机制

消息转发机制有两个比较重要的方法:

forwardInvocation: 具体的NSInvocaion

methodSignatureForSelector: 返回SEL的方法签名


这里不得不提一下两个类:

NSMethodSignature 用来表示方法的参数签名信息:返回值,参数数量和类型

NSInvocaion SEL + 执行SEL的Target + 参数值

通常,拿到NSInvocaion对象后,我们可选择的进行如下操作

修改执行的SEL

修改执行的Target

修改传入的参数

然后调用:[invocation invoke],来执行这个消息。



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