runtime 消息机制
消息机制可以简单分为三个方面:消息发送、动态方法解析、消息转发
一.消息发送
oc 中所有的方法调用最终会通过 runtime 转换为objc_msgSend(obj,@selector(sendMassage))这个函数,有两个隐藏的参数:代表对象的类型、函数对应的方法的编号(SEL),然后通过以下顺序寻找调用:
1.通过obj的isa指针找到其所对应的类
2.通过SEL寻找方法是否存在(1、cache—>2.类的方法列表—>父类----->NSObject)
3.找到之后寻找方法实现(IMP)
寻找 imp 的方法
i class_getMethodImplementation(Class cls, SEL name);
ii method_getImplementation(Method m)
4.调用 imp(self, _cmd, ...)
至此 OC 的消息发送就完成,如果在上述过程中没有对应的方法或者实现,那么OC 的消息机制也会提供其他的机会来防止程序崩溃:动态方法解析和消息转发
二、动态方法解析
如果在消息的发送过程中没有找到对应的方法OC消息机制会提供一个动态解析方法的机会,让我们来动态添加方法的实现
resolveInstanceMethod、 resolveClassMethod
下面是一个🌰:一个看类中掉用了 unImpMethod()方法
但是并未写方法的实现当我们调用的时候会先走第一部分的流程,然后发现并没有找到对应的 imp,此时我们可以通过resolveInstanceMethod来添加一个 imp
//增加一个方法
void esolveInstanceTest(){
NSLog(@"添加啦啦啦啦啦");
}
//动态解析方法
+(BOOL)resolveInstanceMethod:(SEL)sel{
if (sel == @selector(unImpMethod)) {
//动态解析时添加一个方法
class_addMethod([self class], sel, (IMP) esolveInstanceTest, "v@:");
}
return [super resolveInstanceMethod:sel];
}
态解析过程添加IMP并且返回了 yes 就可以完成调用,当这个方法返回no时或者没有实现时会进入消息转发。
三、消息转发
消息转发可以分为两个步骤,
1.先通过forwardingTargetForSelector返回一个实现了该方法的对象。如果此时的对象任然不能响应就会进入消息转发下一个阶段
//该方法返回一个添加了方法实现的对象,
-(id)forwardingTargetForSelector:(SEL)aSelector{
if (aSelector == @selector(unImpMethod)) {
//studentTest类中这个方法有实现
ForwardingTarget *forwardingTarget = [[ForwardingTarget alloc]init];
return forwardingTarget;
}
return [super forwardingTargetForSelector:aSelector];
}
2.runtime需要生成一个methodSignature变量来组装一个NSInvocation对象进行最后一次的消息转发
//这个方法返回一个NSMethodSignature*的对象,里面打包了有关于这个未实现方法的信息
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
NSString*sel = NSStringFromSelector(aSelector);
if ([sel isEqualToString:@"write"]) {
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
return [super methodSignatureForSelector:aSelector];
}
-(void)forwardInvocation:(NSInvocation *)anInvocation{
SEL selector = [anInvocation selector];
StudentTest *test = [[StudentTest alloc]init];
if ([test respondsToSelector:selector]) {
[anInvocation invokeWithTarget:test];
}
}