Runtime中的Method Swizzle

示例: 一鍵改字體

1. 工程的Info.plist文件中需添加:

Info.plist添加內(nèi)容.png

其中l(wèi)oveway.ttf為字體冊(cè)資源文件的名稱.

2. Category類
UILabel+FontChange.h

//
//  UILabel+FontChange.h
//  FontChangeProject
//
//  Created by Brian on 16/02/13.
//  Copyright ? 2016年 Mac. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface UILabel (FontChange)

@end

UILabel+FontChange.m

//
//  UILabel+FontChange.m
//  FontChangeProject
//
//  Created by Brian on 16/02/13.
//  Copyright ? 2016年 Mac. All rights reserved.
//

#import "UILabel+FontChange.h"
#import <objc/runtime.h>

#define CustomFontName @"FZLBJW--GB1-0" // 字體冊(cè).ttf文件中字體的名稱

@implementation UILabel (FontChange)

+ (void)load {
    // 方法交換應(yīng)該保證在程序中只會(huì)被執(zhí)行一次
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        // 1. 獲取UILabel的生命周期方法的selector
        SEL originalSel = @selector(willMoveToSuperview:);
        
        // 2. 獲取自己實(shí)現(xiàn)的將要被交換的方法的selector
        SEL overrideSel = @selector(myWillMoveToSuperview:);
        
        // 3. 實(shí)現(xiàn)方法交換
        MethodSwizzle([self class], originalSel, overrideSel);
    });
}

void MethodSwizzle(Class cls, SEL originalName, SEL overrideName) {
    // 獲取類中的某個(gè)實(shí)例的方法(減號(hào)方法)
    Method originalMethod = class_getInstanceMethod(cls, originalName);
    Method overrideMethod = class_getInstanceMethod(cls, overrideName);
    
    /** 原理: 有兩種情況要考慮一下,
        第一種情況是:要復(fù)寫的方法(override)并沒有在目標(biāo)類中實(shí)現(xiàn);
        第二種情況是:這個(gè)方法(override)已經(jīng)存在于目標(biāo)類中了.
     這兩種情況要區(qū)別對(duì)待.
     
     對(duì)于第一種情況,應(yīng)當(dāng)先在目標(biāo)類中增加一個(gè)新的實(shí)現(xiàn)方法(override),運(yùn)行時(shí)函數(shù)class_addMethod()如果
     發(fā)現(xiàn)該方法已經(jīng)存在,會(huì)返回NO;
     
     對(duì)于第二種情況,因?yàn)閏lass_getInstanceMethod會(huì)返回父類的實(shí)現(xiàn),如果直接替換,就會(huì)替換掉父類的實(shí)現(xiàn),而不是目標(biāo)類中的實(shí)現(xiàn). 
     這時(shí)需要在一個(gè)合適的位置來調(diào)用MethodSwizzle()方法, 在+ (void)load方法中調(diào)用就可以直接完成交換.
    */
    
    
    // class_addMethod()方法會(huì)讓originalName方法指向新的實(shí)現(xiàn)overrideMethod
    BOOL result = class_addMethod(cls, originalName, method_getImplementation(overrideMethod), method_getTypeEncoding(overrideMethod));
    if (result) {
        // 如果添加成功, 表示originalName方法已指向新的實(shí)現(xiàn)overrideMethod, 然后再使用class_replaceMethod()將新的方法overrideName指向原先的實(shí)現(xiàn)originalMethod, 就完成了交換.
        class_replaceMethod(cls, overrideName, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    } else {
        // 如果添加失敗,就是第二種情況,這時(shí)可以直接通過method_exchangeImplementations來完成交換.
        method_exchangeImplementations(originalMethod, overrideMethod);
    }
}

- (void)myWillMoveToSuperview:(UIView *)newSuperview {
    [self myWillMoveToSuperview:newSuperview];
    
    // 自己的處理代碼...
    
    if ([self isKindOfClass:NSClassFromString(@"UIButtonLabel")]) {
        return;
    }
    if (self) {
        if (self.tag == 10086) {
            self.font = [UIFont systemFontOfSize:self.font.pointSize];
        } else {
            if ([UIFont fontNamesForFamilyName:CustomFontName]) {
                self.font = [UIFont fontWithName:CustomFontName size:self.font.pointSize];
            }
        }
    }
}

@end

Tips: 獲取字體冊(cè)中的字體名稱

/**
 讀取ttf或otf字體冊(cè)中的字體名稱 (先在Info.plist中把字體文件名添加到Fonts provided by application一項(xiàng)中)

 @param path 字體冊(cè)文件的路徑 如:[[NSBundle mainBundle] pathForResource:@"font12" ofType:@"ttf"]
 @param size 字體大小 如:18
 @return 字體
 */
- (UIFont *)customFontWithPath:(NSString *)path size:(CGFloat)size {
    NSURL *fontUrl = [NSURL fileURLWithPath:path];
    CGDataProviderRef fontDataProvider = CGDataProviderCreateWithURL((__bridge CFURLRef)fontUrl);
    CGFontRef fontRef = CGFontCreateWithDataProvider(fontDataProvider);
    CGDataProviderRelease(fontDataProvider);
    CTFontManagerRegisterGraphicsFont(fontRef, NULL);
    NSString *fontName = CFBridgingRelease(CGFontCopyPostScriptName(fontRef));
    NSLog(@"fontName = %@", fontName);
    UIFont *font = [UIFont fontWithName:fontName size:size];
    CGFontRelease(fontRef);
    return font;
}

/**
 讀取ttc字體冊(cè)中的字體名稱 (先在Info.plist中把字體文件名添加到Fonts provided by application一項(xiàng)中)

 @param path 字體冊(cè)文件的路徑 如:[[NSBundle mainBundle] pathForResource:@"font12" ofType:@"ttc"]
 @param size 字體大小 如:18
 @return 字體數(shù)組
 */
- (NSArray *)customFontArrayWithPath:(NSString *)path size:(CGFloat)size {
    CFStringRef fontPath = CFStringCreateWithCString(NULL, [path UTF8String], kCFStringEncodingUTF8);
    CFURLRef fontUrl = CFURLCreateWithFileSystemPath(NULL, fontPath, kCFURLPOSIXPathStyle, 0);
    CFArrayRef fontArray = CTFontManagerCreateFontDescriptorsFromURL(fontUrl);
    CTFontManagerRegisterFontsForURL(fontUrl, kCTFontManagerScopeNone, NULL);
    
    NSMutableArray *customFontArray = [NSMutableArray array];
    for (CFIndex i = 0; i < CFArrayGetCount(fontArray); i++) {
        CTFontDescriptorRef descriptor = CFArrayGetValueAtIndex(fontArray, i);
        CTFontRef fontRef = CTFontCreateWithFontDescriptor(descriptor, size, NULL);
        NSString *fontName = CFBridgingRelease(CTFontCopyName(fontRef, kCTFontPostScriptNameKey));
        NSLog(@"fontName[%ld] = %@", i, fontName);
        UIFont *font = [UIFont fontWithName:fontName size:size];
        [customFontArray addObject:font];
    }
    return customFontArray; 
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市逾雄,隨后出現(xiàn)的幾起案子弦叶,更是在濱河造成了極大的恐慌呈野,老刑警劉巖旗闽,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件遵馆,死亡現(xiàn)場(chǎng)離奇詭異京腥,居然都是意外死亡赦肃,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門公浪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來他宛,“玉大人,你說我怎么就攤上這事欠气《楣” “怎么了?”我有些...
    開封第一講書人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵晃琳,是天一觀的道長(zhǎng)讯检。 經(jīng)常有香客問我,道長(zhǎng)卫旱,這世上最難降的妖魔是什么人灼? 我笑而不...
    開封第一講書人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮顾翼,結(jié)果婚禮上投放,老公的妹妹穿的比我還像新娘。我一直安慰自己适贸,他們只是感情好灸芳,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著拜姿,像睡著了一般烙样。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蕊肥,一...
    開封第一講書人閱讀 51,573評(píng)論 1 305
  • 那天谒获,我揣著相機(jī)與錄音,去河邊找鬼壁却。 笑死批狱,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的展东。 我是一名探鬼主播赔硫,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼盐肃!你這毒婦竟也來了爪膊?” 一聲冷哼從身側(cè)響起向胡,我...
    開封第一講書人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎惊完,沒想到半個(gè)月后僵芹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡小槐,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年拇派,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片凿跳。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡件豌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出控嗜,到底是詐尸還是另有隱情茧彤,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布疆栏,位于F島的核電站曾掂,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏壁顶。R本人自食惡果不足惜珠洗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望若专。 院中可真熱鬧许蓖,春花似錦、人聲如沸调衰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嚎莉。三九已至米酬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間萝喘,已是汗流浹背淮逻。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工琼懊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留阁簸,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓哼丈,卻偏偏與公主長(zhǎng)得像启妹,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子醉旦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容