iOS runtime学习之Method Swizzling(方法调配技术)

Object-C对象收到消息后,究竟会调用何种方法需要在运行期才能解析出来。那也许就会问,与给定的选择子名称相对应的方法是不是也可以在运行期改变呢?答案是肯定的。若善用此特性,则可发挥巨大优势,因为我们既不需要源代码,也不需要通过通过继承子类来覆写方法就能改变这个类本身的功能。这样一来,新功能将在本类的所有实例中生效,而不是仅限于覆写了相关方法的那些子类实例。此方案经常成为“方法调配”(Method Swizzling)。
(1)在运行期,可以向类中新增或替换选择子所对应的方法实现
(2)使用另一份实现替换原来方法的实现,这叫“方法调配”,此技术可向原有实现中添加新功能
(3)不宜滥用

@implementation UIViewController (Logging)

+ (void)load {
    swizzleMethod([self class], @selector(viewDidAppear:), @selector(swizzle_viewDidAppear:));
}

- (void)swizzle_viewDidAppear:(BOOL)animated {
    [self swizzle_viewDidAppear:animated]; //看着好像是递归,不过大家记住,这个方法是准备和viewDidAppear这儿方法互换的。所以,在运行期,swizzle_viewDidAppear选择子实际上对应于原有的viewDidAppear方法的实现
    NSLog(@"logging: %@", NSStringFromClass([self class]));
}

void swizzleMethod(Class class, SEL originalSelector, SEL swizzleSelector) {
    Method originalMethod = class_getInstanceMethod(class, originalSelector);
    Method swizzleMethod = class_getInstanceMethod(class, swizzleSelector);

    /* 
        class_addMethod,可以向类中动态的添加方法,用以处理选择子。
        尝试添加原selector做一层保护,如果这个类没有实现originalSelector,但其父类实现了,那么class_getInstanceMethod方法返回的是父类的方法。这样的话替换的就是父类的方法,不是我们希望的。所以尝试添加originalSelector,如果已经存在,在用method_exchangeImplementations把原方法的实现和新方法的实现交换。
     */
    BOOL success = class_addMethod(class, originalSelector, method_getImplementation(swizzleMethod), method_getTypeEncoding(swizzleMethod));
    if (success) {
        class_replaceMethod(class, swizzleSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    } else {
        method_exchangeImplementations(originalMethod, swizzleMethod);
    }
}

参考:http://tech.glowing.com/cn/method-swizzling-aop/
《52个有效方法》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值