runTimeでアイテム内のフォントを変更することについて

2715 ワード

本人のプロジェクトはもうすぐ2年更新して、突然appの中のフォントを変更することを要求して、もし伝統的な方式によって1つ1つlabel、button、textfieldなどfontを通じて変えるならば、私は血を吐くことができて、runTimeで初期化の方法を変えることを考えました.これが一番便利な方法だと思います.
まずコードをつけて、それから私が入った穴をみんなに話します.
+ (void)load {
    [super load];
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        //  init  
        SEL origialSEL1        = @selector(init);
        SEL swizzledSEL1       = @selector(LY_init);
        [self swizzledMethodWithOriginalSEL:origialSEL1 withSwizzledSEL:swizzledSEL1];
        
        //  initWithFrame  
        SEL origialSEL2        = @selector(initWithFrame:);
        SEL swizzledSEL2       = @selector(LY_initWithFrame:);
        [self swizzledMethodWithOriginalSEL:origialSEL2 withSwizzledSEL:swizzledSEL2];
       
        //  awakeFromNib  
        SEL origialSEL3        = @selector(awakeFromNib);
        SEL swizzledSEL3       = @selector(LY_awakeFromNib);
        [self swizzledMethodWithOriginalSEL:origialSEL3 withSwizzledSEL:swizzledSEL3];
        
    });
}

+ (void)swizzledMethodWithOriginalSEL:(SEL)originalSEL withSwizzledSEL:(SEL)swizzledSEL {
    
    Class class = [self class];
    Method originalMethod = class_getInstanceMethod(class, originalSEL);
    Method swizzledMethod = class_getInstanceMethod(class, swizzledSEL);
    BOOL didAddMethod = class_addMethod(class, originalSEL, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
    if (didAddMethod) {
        class_replaceMethod(class, swizzledSEL, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    } else {
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
    
}


- (instancetype)LY_init
{
    id __self = [self LY_init];
    if (__self) {
        
    }
    return __self;
}


- (instancetype)LY_initWithFrame:(CGRect)frame
{
    id __self = [self LY_initWithFrame:frame];
    if (self) {
        
    }
    return __self;
}

- (void)LY_awakeFromNib {
    [self LY_awakeFromNib];
    
}


まずコードについて説明します.+(void)load{}この方法はlabelをロードする前にこの方法を実行します.この方法はmain関数の前に行きます.方法交換を保証するために1回しか歩かないので、dispatch_を使いました.once、そして次の3つの方法では、初期化時、例えばLY_Initメソッドでは、id__が初期化されています.self = [self LY_init];一部の子供靴はこれが本类の中で自分を呼び出すのではありませんて、あれは死循环ではありませんか、みんなはこの地方の方法の名称がすでに交换したことを覚えていて、だから[self LY_init]この地方は実际にシステムのinitの方法を指します.ここは要注意...
以下は私が入った穴で、たくさん...まずはclassというところで、私が使い始めたのはClass class=object_getClass((id)self); そして入手したmethodが空であることを発見し、後で資料を見てからクラスメソッドがこのclassインスタンスメソッドであればClass class=[self class]を使用することを発見した.一つはMethod originalMethod=class_getInstanceMethod(class, originalSEL);methodを手に入れた時もクラスメソッドclass_getClassMethod. 皆さんがやるときは、クラスメソッドかインスタンスメソッドかに注意してください.の