Objective-C Runtime 运行时(3)

Method Swizzling:方法混淆,顾名思义将两个方法交换,即由A-AIMP,B-BIMP变成A-BIMP,B-AIMP。
方法混淆原理:每个类都有一个方法(Method)列表,Method包含SEL和IMP的对应关系,方法交换就是将SEL和IMP的关系断开,并和新的IMP生成新的对应关系。
相关函数介绍

//获取通过SEL获取一个方法
class_getInstanceMethod
//获取一个方法的实现
method_getImplementation
//給方法添加实现
class_addMethod
//用一个方法的实现替换另一个方法的实现
class_replaceMethod
//交换两个方法的实现
method_exchangeImplementations

方法混淆应保证唯一性和原子性,由于ios内部实现不可见,因此方法混淆可能会导致代码结构改变,因此应该调用原始实现来保证操作的正常运行。
应用举例:
(1)hook:修改UIImage的imageNamed方法。

@implementation UIImage (Hook)

+ (void)load {

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

        Class selfClass = object_getClass([self class]);

        SEL oriSEL = @selector(imageNamed:);
        Method oriMethod = class_getInstanceMethod(selfClass, oriSEL);

        SEL cusSEL = @selector(myImageNamed:);
        Method cusMethod = class_getInstanceMethod(selfClass, cusSEL);

        BOOL addSucc = class_addMethod(selfClass, oriSEL, method_getImplementation(cusMethod), method_getTypeEncoding(cusMethod));
        if (addSucc) {
            class_replaceMethod(selfClass, cusSEL, method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod));
        }else {
            method_exchangeImplementations(oriMethod, cusMethod);
        }

    });
}

+ (UIImage *)myImageNamed:(NSString *)name {
    return [self myImageNamed:newName];
}

@end

代码调用了[self myImageNamed:newName],看起来会陷入死循环,但其实myImageNamed的实现已经是imageNamed(IMP),因此该调用相当于调用系统原来的生成图片的实现。
(2)面向切面编程: 数据统计

@implementation UIButton (Hook)

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class selfClass = [self class];
        SEL oriSEL = @selector(sendAction:to:forEvent:);
        Method oriMethod = class_getInstanceMethod(selfClass, oriSEL);

        SEL cusSEL = @selector(mySendAction:to:forEvent:);
        Method cusMethod = class_getInstanceMethod(selfClass, cusSEL);

        BOOL addSucc = class_addMethod(selfClass, oriSEL, method_getImplementation(cusMethod), method_getTypeEncoding(cusMethod));
        if (addSucc) {
            class_replaceMethod(selfClass, cusSEL, method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod));
        }else {
            method_exchangeImplementations(oriMethod, cusMethod);
        }

    });
}
- (void)mySendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
    [CountTool addClickCount];
    [self mySendAction:action to:target forEvent:event];
}
@end

Method Swizzling是OC动态性的最好诠释,深入地去学习并理解其特性,将有助于我们在业务量不断增大的同时还能保持代码的低耦合度,降低维护的工作量和难度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值