概况
当一个方法沿着类的继承链找不到实现时候,runtime会启动消息转发。消息转发一共有三步。
消息转发三步
- resolveInstanceMethod
#import "Cat.h"#import@implementation Cat+ (BOOL)resolveInstanceMethod:(SEL)sel{ if ([NSStringFromSelector(sel) isEqualToString:@"say"]) { class_addMethod(self, sel,(IMP)test , "v@:"); return YES; } return [super resolveInstanceMethod:sel];}void test(id self,SEL cmd){ NSLog(@"猫叫...");}@end复制代码
@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; Cat *aCat = [[Cat alloc] init]; [aCat say];}@end复制代码
在调用对象的所属类的实现文件新增resolveInstanceMethod方法。判断选择子是不是我们要进行转发的,如果不是返回super方法。如果是就新增方法的实现,并返回YES消息转发结束。
- forwardingTargetForSelector
#import "Dog.h"#import "Cat.h"#import@implementation Dog+ (BOOL)resolveInstanceMethod:(SEL)sel{ if ([NSStringFromSelector(sel) isEqualToString:@"say"]) { return NO; } return [super resolveInstanceMethod:sel];}- (id)forwardingTargetForSelector:(SEL)aSelector{ return [Cat new];}@end复制代码
@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; Dog *aDog = [[Dog alloc] init]; [aDog say];}@end复制代码
在调用所属类的实现文件里新增resolveInstanceMethod方法如果是当前选择子返回NO好进行消息转发第二步。接下来新增方法forwardingTargetForSelector返回cat对象。之后runtime系统会去cat类里去调用say的实现。
- forwardInvocation
#import "Dog.h"#import "Cat.h"#import@implementation Dog+ (BOOL)resolveInstanceMethod:(SEL)sel{ if ([NSStringFromSelector(sel) isEqualToString:@"say"]) { return NO; } return [super resolveInstanceMethod:sel];}- (id)forwardingTargetForSelector:(SEL)aSelector{ return nil;}- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{ return [NSMethodSignature signatureWithObjCTypes:"v@:"];}- (void)forwardInvocation:(NSInvocation *)anInvocation{ SEL aSel = anInvocation.selector; Cat *aCate = [Cat new]; if ([aCate respondsToSelector:aSel]) { [anInvocation invokeWithTarget:aCate]; }}@end复制代码
在调用类的实现文件里,新增resolveInstanceMethod方法返回NO,进入消息转发第二步。新增forwardingTargetForSelector方法返回nil,进入消息转发第三步。新增方法methodSignatureForSelector,forwardInvocation实现完整的消息转发。