iOS充电知识点

iOS 方法交换 method_exchangeImplemen

2021-07-31  本文已影响0人  _Waiting_

熟知runtime的小伙伴都知道,方法是可以进行动态交换的,额,遇到一个问题,怎么样把所有界面上的字体调大10个字号?
提供一种方法,利用runtime的method_exchangeImplementations进行方法交换,可以达到目的。(也可以在分类中继承父类,重写方法进行)。

#import "UIFont+Han.h"
#import <objc/runtime.h>

//不管是类还是分类都会加载并且只会加载一次load,因为load是指针直接调用
+(void)load{
    //由于修改的是类方法,所以要传入源类对像
    [self hookClass:object_getClass(self) originalSelector:@selector(systemFontOfSize:) swizzledSelector:@selector(han_systemFontOfSize:)];
}

+ (UIFont *)han_systemFontOfSize:(CGFloat)fontSize{
    
    //当方法交换后调用han_systemFontOfSize及调用系统的systemFontOfSize
    //当方法交换后调用systemFontOfSize及调用自己定义的han_systemFontOfSize
    UIFont *font = [self han_systemFontOfSize:fontSize + 10];
    return font;
    
}
+ (void)hookClass:(Class)classObject originalSelector:(SEL)originalSelector swizzledSelector:(SEL)swizzledSelector {
    Class class = classObject;

    //如果本类中有 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,添加失败,那就直接交换了
    //如果本类中,没有此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);
}

上一篇下一篇

猜你喜欢

热点阅读