美文网首页
方法调用以及转发流程

方法调用以及转发流程

作者: 北京好挤 | 来源:发表于2019-03-19 19:30 被阅读0次

    首先理解几个名词:

    1.SEL :Objective-C 在编译时,会根据方法的名字生成一个用来区分这个方法的唯一的一个ID,本质上就是一个字符串。只要方法名称相同,那么它们的ID就是相同的。

    2.Method:

    3.IMP

    方法调用查找流程

    检查 selector 是否需要忽略

    检查 target 是否为 nil,如果是 nil 就直接 cleanup,然后 return

    在 target 的 Class 中根据 selector 去找 IMP

    寻找 IMP 的过程[2]:

    在当前 class 的方法缓存里寻找(cache methodLists)

    找到了跳到对应的方法实现,没找到继续往下执行

    从当前 class 的 方法列表里查找(methodLists),找到了添加到缓存列表里,然后跳转到对应的方法实现;没找到继续往下执行

    从 superClass 的缓存列表和方法列表里查找,直到找到基类为止

    以上步骤还找不到 IMP,则进入消息动态处理和消息转发流程

    方法转发流程

    1.消息动态处理

    voiddynamicMethodIMP(idself, SEL _cmd)

    {// implementation ....}

    + (BOOL)resolveInstanceMethod:(SEL)sel

    {

    NSLog(@"sel is %@",NSStringFromSelector(sel));

    if(sel ==@selector(setName:))

     class_addMethod([selfclass],sel,(IMP)dynamicMethodIMP,"v@:");

    returnYES; 

     }

    return [superresolveInstanceMethod:sel];

    }

    - (id)forwardingTargetForSelector:(SEL)aSelector

    {

    //如果代理对象能处理,则转接给代理对象if([proxyObj respondsToSelector:aSelector]) {returnproxyObj;

     }

    //不能处理进入转发流程returnnil;

    }

    2.消息转发

    <pre>

    - (NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector{NSMethodSignature*sig = [BBMessageForwardProxy instanceMethodSignatureForSelector:@selector(bb_dealNotRecognizedMessage:)];returnsig;}- (void)forwardInvocation:(NSInvocation*)anInvocation{NSString*debugInfo = [NSStringstringWithFormat:@"[debug]unRecognizedMessage:[%@] sent to [%@]",NSStringFromSelector(anInvocation.selector),NSStringFromClass([selfclass])];//重定向方法[anInvocation setSelector:@selector(bb_dealNotRecognizedMessage:)];//传递调用信息[anInvocation setArgument:&debugInfo atIndex:2];//BBMessageForwardProxy对象接收转发的消息并打印调用信息[anInvocation invokeWithTarget:[BBMessageForwardProxy new]];}

    </pre>

    如果 methodSignatureForSelector 返回的NSMethodSignature 是 nil 的话不会继续执行 forwardInvocation,转发流程终止,抛出无法处理的异常。

    Class和MetaClass

    当我们对一个实例发送消息时(-开头的方法),会在该 instance 对应的类的 methodLists 里查找。

    当我们对一个类发送消息时(+开头的方法),会在该类的 MetaClass 的 methodLists 里查找。

    load和initialize

    我们知道了 load 是在被添加到 runtime 时开始执行,父类最先执行,然后是子类,最后是 Category。又因为是直接获取函数指针来执行,不会像 objc_msgSend 一样会有方法查找的过程。

    initialize 最终是通过 objc_msgSend 来执行的,objc_msgSend 会执行一系列方法查找,并且 Category 的方法会覆盖类中的方法。

    category

    相关文章

      网友评论

          本文标题:方法调用以及转发流程

          本文链接:https://www.haomeiwen.com/subject/ybinmqtx.html