在OC中,当像一个对象发送消息,而对象找到消息后,从它的类方法列表,父类方法列表,一直找到根类方法列表都没有找到与这个选择子对应的函数指针。那么这个对象就会触发消息转发机制。
OC对象的继承链和isa指针链如图:
image.png消息转发流程如下:
1.先调用实例方法resolveInstanceMethod
如果作者在这里使用runtime动态添加对应的方法,并且返回yes。就万事大吉。对象找到了处理的方法,
并且将这个新增的方法添加到类的方法缓存列表
2.如果上面的方法返回NO的话,对象会调用forwardingTargetForSelector方法
允许作者选择其他的对象,处理这个消息。
这个方法,也是待会我们要做文章的地方。画重点。
3.如果上面两个方法都没有做处理,那么对象会执行最后一个方法methodSignatureForSelector,提供一个有效的方法签名,若提供了有效的方法签名,程序将会通过forwardInvocation方法执行签名。若没有提供方法签名就会触发doesNotRecognizeSelector方法,触发崩溃。
整个调用流程图如下:
image.png整个代码调用顺序如下:
//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:14:00.469445+0800 iOS_KnowledgeStructure[7940:110114] 1---gogogo
2018-12-27 00:14:00.469613+0800 iOS_KnowledgeStructure[7940:110114] 1---resolveInstanceMethod:
2018-12-27 00:14:00.469765+0800 iOS_KnowledgeStructure[7940:110114] 2---gogogo
2018-12-27 00:14:00.469873+0800 iOS_KnowledgeStructure[7940:110114] 2---forwardingTargetForSelector:
2018-12-27 00:14:00.469978+0800 iOS_KnowledgeStructure[7940:110114] 3---gogogo
2018-12-27 00:14:00.470097+0800 iOS_KnowledgeStructure[7940:110114] 3---methodSignatureForSelector:
2018-12-27 00:14:00.470247+0800 iOS_KnowledgeStructure[7940:110114] 1---_forwardStackInvocation:
2018-12-27 00:14:00.470355+0800 iOS_KnowledgeStructure[7940:110114] 1---resolveInstanceMethod:
2018-12-27 00:14:00.470765+0800 iOS_KnowledgeStructure[7940:110114] 4---forwardInvocation:
2018-12-27 00:14:00.471367+0800 iOS_KnowledgeStructure[7940:110114] 4-最后一步--<NSInvocation: 0x600002442000>
2018-12-27 00:14:00.471969+0800 iOS_KnowledgeStructure[7940:110114] lalalalala---gogogo
网友评论