runtime(消息转发)

概况

当一个方法沿着类的继承链找不到实现时候,runtime会启动消息转发。消息转发一共有三步。

消息转发三步

  1. resolveInstanceMethod
#import "Cat.h"
#import <objc/runtime.h>

@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消息转发结束。

  1. forwardingTargetForSelector
#import "Dog.h"
#import "Cat.h"
#import <objc/runtime.h>

@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的实现。

  1. forwardInvocation
#import "Dog.h"
#import "Cat.h"
#import <objc/runtime.h>

@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实现完整的消息转发。

猜你喜欢

转载自blog.csdn.net/qq_17190231/article/details/87093962
今日推荐