runtime方法交换

2020-03-27  本文已影响0人  85ca4232089b

#import "UIImage+customer.h"
#import <objc/runtime.h>

@implementation UIImage (customer)
+ (void)load{

    /**
     *  我们在这里使用class_addMethod()函数对Method Swizzling做了一层验证,如果self没有实现被交换的方法,会导致失败。
     *  而且self没有交换的方法实现,但是父类有这个方法,这样就会调用父类的方法,结果就不是我们想要的结果了。
     *  所以我们在这里通过class_addMethod()的验证,如果self实现了这个方法,class_addMethod()函数将会返回NO,我们就可以对其进行交换了。
     */

        Class class2 = object_getClass(self);
    
    /**
     * 对象方法是依实例方法的形式存在类当中的。 [self class]
     * 类方法是依实例方法的形式存在元类当中的   class2
     */
    [self hookClass:class2 originalSelector:@selector(swizzlingImageName:) swizzledSelector:@selector(imageNamed:)];
    [self hookClass:[self class] originalSelector:@selector(swizzlingInitWithData:) swizzledSelector:@selector(initWithData:)];

}
+ (void)hookClass:(Class)classObject originalSelector:(SEL)originalSelector swizzledSelector:(SEL)swizzledSelector {
    Class class = classObject;
    //第三版Hook核心思想是,
    //如果本类中有 originalSelector 方法,直接交换。
    //如果本类中没有 originalSelector 方法,添加父类的的方法到子类,然后再直接交换。
    
    // 这两行与以前没有任何变化
    Method originalMethod = class_getInstanceMethod(class, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
    
    //class_addMethod 添加的SEL是 originalSelector ,IMP 是 method_getImplementation(originalMethod),我称他们为原配,
    //如果本类中,已经有 originalSelector,再添加 originalSelector, 肯定返回NO,添加失败,那就直接交换了,跟第一版hook流程一模一样了,
    //如果本类中,没有此SEL,那就会去父类里找,返回的就是父类里的信息,然后将父类的信息,添加到本类中,就相当于,本类完全的继承了父类的方法,
    BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    if (didAddMethod) {
        //添加成功后,本类中,已经有一个originalSelector方法了
        //我们第一次获得originalMethod是返回父类的originalMethod
        //我们需要再重新获得一下originalMethod,这次返回的不是父类的originalMethod
        //而是我们刚刚class_addMethod添加的到本类的originalMethod
        
        originalMethod = class_getInstanceMethod(class, originalSelector);
    }
    
    //走到这,就证明了,本类中肯定已经有这两个方法了,那就这样直接交换吧。
    method_exchangeImplementations(swizzledMethod, originalMethod);
}
+ (instancetype)swizzlingImageName:(NSString*)name{


    name = [NSString stringWithFormat:@"test_1"];
    return [self swizzlingImageName:name];
}
- (instancetype)swizzlingInitWithData:(NSData*)data{

    NSLog(@"===========");
    return [self swizzlingInitWithData:data];
}
@end

上一篇 下一篇

猜你喜欢

热点阅读