美文网首页
Runtime运行时二:方法

Runtime运行时二:方法

作者: Carson_Zhu | 来源:发表于2018-02-02 12:54 被阅读9次

SEL

SEL又叫选择器,是表示一个方法的selector的指针,其定义如下:

typedef struct objc_selector *SEL;

方法的selector用于表示运行时方法的名字。Objective-C在编译时,会依据每一个方法的名字、参数序列,生成一个唯一的整型标识(Int类型的地址),这个标识就是SEL。两个类之间,只要方法名相同,那么方法的SEL就是一样的,每一个方法都对应着一个SEL。所以在Objective-C同一个类(及类的继承体系)中,不能存在2个同名的方法,即使参数类型不同也不行。

方法调用
[self testMethod:@"数据"];
[self performSelector:@selector(testMethod:) withObject:@"数据"];
// Runtime
objc_msgSend(self, @selector(testMethod:), @"数据");

iOS8之后报错

// 用函数指针,指向了runtime的objc_msgSend方法才能调用,不能直接调用objc_msgSend()
void (*runtime_msgSend)(id self, SEL _cmd, id param) = (void *)objc_msgSend;

runtime_msgSend(self.methodHelper, NSSelectorFromString(@"testMethod:"), @"hello world");
动态决议

对象在接收到未知的消息时,首先会调用所属类的类方法。我们为该未知消息新增一个“处理方法”,通过运行时class_addMethod函数动态添加到类里面就可以了。

// 接收处理未知实例方法
+ (BOOL)resolveInstanceMethod:(SEL)sel {  
    if ([NSStringFromSelector(sel) isEqualToString:@"testMethod:"]) {
        if (!class_addMethod([self class], sel, (IMP)testMethodImplementation, "v@:@")
            ) {
            NSLog(@"动态添加方法失败");
        }
    }
    return [super resolveInstanceMethod:sel];
}

// 接收处理未知类方法
+ (BOOL)resolveClassMethod:(SEL)sel {
    // 动态添加类方法
    return [super resolveClassMethod:sel];
}

必须要有动态添加方法的实现

void testMethodImplementation(id self, SEL _cmd, id param) {
    NSLog(@"这是动态创建的方法的实现");
}

适用场景:
使用关键字@dynamic在类的实现文件中修饰一个属性,表明我们会为这个属性动态提供存取方法,编译器不会再默认为我们生成这个属性的settergetter方法了,需要我们自己提供。

消息转发
  • 第一种方式:
- (id)forwardingTargetForSelector:(SEL)aSelector {    
    if ([self.methodHelper respondsToSelector:aSelector]) {
        return self.methodHelper;
    }
    return [super forwardingTargetForSelector:aSelector];
}
  • 第二种方式:
- (void)forwardInvocation:(NSInvocation *)anInvocation {
    if ([self.methodHelper respondsToSelector:anInvocation.selector]) {
        [anInvocation invokeWithTarget:self.methodHelper];
    }
}
方法交换

当系统类的方法不能满足我们的需求,比如你想在所有的UIViewControllerviewWillAppear里设置背景颜色,你可以写一个Base类,然后去继承。你也可以选择Runtime的方法交换。

  • 第一步
    导入ObjectiveC
@import ObjectiveC;
  • 第二步
    创建一个UIViewController的Category,实现+ (void)load方法
+ (void)load {
    // class_getInstanceMethod 获取对象方法
    // class_getClassMethod    获取类方法
    
    // 获取系统的viewWillAppear方法
    Method viewWillAppearMethod = class_getInstanceMethod([UIViewController class], @selector(viewWillAppear:));
    // 获取自定义的bgViewWillAppear方法
    Method bgViewWillAppearMethod = class_getInstanceMethod([UIViewController class], @selector(bgViewWillAppear:));
    // 交换方法实现
    method_exchangeImplementations(viewWillAppearMethod, bgViewWillAppearMethod);
}
  • 第三步
    实现自定义的方法,并调用(因为方法交换了,实际上调用的是系统的方法)
- (void)bgViewWillAppear:(BOOL)animated {
    self.view.backgroundColor = [UIColor redColor];
    [self bgViewWillAppear:animated];
}

相关文章

网友评论

      本文标题:Runtime运行时二:方法

      本文链接:https://www.haomeiwen.com/subject/vvmszxtx.html