实例方法的流程
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],来执行这个消息。
网友评论