方法调用以及转发流程

首先理解几个名词:

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.消息转发

- (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]];}

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

Class和MetaClass

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

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

load和initialize

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

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

category

你可能感兴趣的:(方法调用以及转发流程)