在OC中,当像一个对象发送消息,而对象找到消息后,从它的类方法列表,父类方法列表,一直找到根类方法列表都没有找到与这个选择子对应的函数指针。那么这个对象就会触发消息转发机制。
OC对象的继承链和isa指针链如图:

消息转发流程如下:
1.先调用实例方法resolveInstanceMethod
如果作者在这里使用runtime动态添加对应的方法,并且返回yes。就万事大吉。对象找到了处理的方法,
并且将这个新增的方法添加到类的方法缓存列表
2.如果上面的方法返回NO的话,对象会调用forwardingTargetForSelector方法
允许作者选择其他的对象,处理这个消息。
这个方法,也是待会我们要做文章的地方。画重点。
3.如果上面两个方法都没有做处理,那么对象会执行最后一个方法methodSignatureForSelector,提供一个有效的方法签名,若提供了有效的方法签名,程序将会通过forwardInvocation方法执行签名。若没有提供方法签名就会触发doesNotRecognizeSelector方法,触发崩溃。
整个调用流程图如下:

整个代码调用顺序如下:
//1+ (BOOL)resolveClassMethod:(SEL)sel { NSLog(@"1---%@",NSStringFromSelector(sel)); NSLog(@"1---%@",NSStringFromSelector(_cmd)); return NO; } + (BOOL)resolveInstanceMethod:(SEL)sel { NSLog(@"1---%@",NSStringFromSelector(sel)); NSLog(@"1---%@",NSStringFromSelector(_cmd)); return NO; } //2- (id)forwardingTargetForSelector:(SEL)aSelector { NSLog(@"2---%@",NSStringFromSelector(aSelector)); NSLog(@"2---%@",NSStringFromSelector(_cmd)); return nil; } //3.最后一步,返回方法签名-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{ NSLog(@"3---%@",NSStringFromSelector(aSelector)); NSLog(@"3---%@",NSStringFromSelector(_cmd)); if ([NSStringFromSelector(aSelector) isEqualToString:@"gogogo"]) { return [[UnknownModel2 new] methodSignatureForSelector:aSelector]; } return [super methodSignatureForSelector:aSelector]; } //3.1处理返回的方法签名-(void)forwardInvocation:(NSInvocation *)anInvocation{ NSLog(@"4---%@",NSStringFromSelector(_cmd)); NSLog(@"4-最后一步--%@",anInvocation); if ([NSStringFromSelector(anInvocation.selector) isEqualToString:@"gogogo"]) { [anInvocation invokeWithTarget:[UnknownModel2 new]]; }else{ [super forwardInvocation:anInvocation]; } } //触发崩溃- (void)doesNotRecognizeSelector:(SEL)aSelector { }
打印结果如下:
2018-12-27 00:

