在項(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ě)方法:

會(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)題不妨一試!