利用iOS的runtime改變字體

在項(xiàng)目開(kāi)發(fā)中有可能遇到一種情況是,項(xiàng)目已經(jīng)開(kāi)發(fā)到一半或者已經(jīng)完成了,這時(shí)候產(chǎn)品經(jīng)理說(shuō) “來(lái),把APP上的所有字體改成‘xxx’字體”!以下有三種方法可以達(dá)成此需求。

繼承

可以寫(xiě)一個(gè)繼承自UIFont的類(lèi),在里面自定義一個(gè)設(shè)置字體的方法,在用到設(shè)置字體的時(shí)候都調(diào)用這個(gè)方法就可以了。但這樣做有一個(gè)明顯的缺點(diǎn):項(xiàng)目里有很地方都要用到設(shè)置字體,就需要把所有相應(yīng)設(shè)置字體的方法改成你自定義的方法,工作量巨大,容易出差錯(cuò)。

category

其實(shí)要達(dá)成這個(gè)目的還可以為UIFont建立一個(gè)category,重寫(xiě)systemFontOfSize:,覆蓋它的原有方法實(shí)現(xiàn),但是這樣做就無(wú)法調(diào)用系統(tǒng)原有的方法,而且蘋(píng)果也不建議在category中重寫(xiě)方法:

category重寫(xiě)systemFontOfSize.png

會(huì)出現(xiàn)上圖中警告

所以我們的解決方法就是利用iOS的runtime另寫(xiě)一個(gè)方法來(lái)和systemFontOfSize:交換。

利用runtime另寫(xiě)一個(gè)方法來(lái)和systemFontOfSize:交換

  • Method Swizzling

主要通過(guò)以下面的方法來(lái)交換
method_exchangeImplementations(originalMethod, swizzledMethod);

+  (void)load{
 //只執(zhí)行一次這個(gè)方法
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class class = [self class];
        SEL originalSelector = @selector(systemFontOfSize:);
        SEL swizzledSelector = @selector(mysystemFontOfSize:);
        // Class class = class_getInstanceMethod((id)self);
        Method originalMethod = class_getClassMethod(class, originalSelector);
        Method swizzledMethod = class_getClassMethod(class, swizzledSelector);
        BOOL didAddMethod = class_addMethod(class,originalSelector,
                                            method_getImplementation(swizzledMethod),
                                            method_getTypeEncoding(swizzledMethod));
        if (didAddMethod)
        {
            class_replaceMethod(class,swizzledSelector,
                                method_getImplementation(originalMethod),
                                method_getTypeEncoding(originalMethod));
            
        }
        else
        {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    });
}

  • IMP指針

IMP是“Implementation”的縮寫(xiě),它指向一個(gè)方法的實(shí)現(xiàn),每個(gè)方法都對(duì)應(yīng)一個(gè)IMP,我們可以直接調(diào)用指針來(lái)達(dá)到目的。

#import "UIFont+changeFont.h"
#import <objc/runtime.h>
#define CustomFontName @"Menlo-Regular"
typedef id (*_IMP)(id,SEL,...);  // 有返回值
typedef id (*_VIMP)(id,SEL,...); // 無(wú)返回值
@implementation UIFont (changeFont)
+(void)load{
static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{ 
         Method systemFontOfSize = class_getClassMethod(self, @selector(systemFontOfSize:));
         _IMP systemFontOfSize_IMP = (_IMP)method_getImplementation(systemFontOfSize);
        method_setImplementation(systemFontOfSize, imp_implementationWithBlock(^(id target,SEL action,CGFloat fontSize){ 
            systemFontOfSize_IMP(target,@selector(systemFontOfSize:));
            UIFont *font = [UIFont fontWithName:CustomFontName size:fontSize];
            return font;
        }));
});
@end

直接調(diào)用IMP指針是一種高效簡(jiǎn)單的方法,以后有類(lèi)似的問(wèn)題不妨一試!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容