Objective-C Runtime使用之全域性字型替換為第三方字型(iOS)
前言:
iOS開發裡頭,常用的設定字型方式是使用UIFont的systemFontOfSize這個Class Method,在一半情況下都算夠用。
最近有設計師朋友問能不能在客戶端中使用特定的字型,答案是可以的,我們可以通過手動給工程新增配置字型的ttf檔案(字型庫)
然後通過fontWithName:name size:size這個 Class Method即可選用,然而在一個已經經過長時間開發的客戶端,會有歷史遺漏問題
導致整個工程的字型配置可能存在修改工作量大,改漏改錯等情況,針對這種情況我們也可以通過runtime來解決。
1、匯入第三方字型
首先需要下載一個.ttf為字尾的檔案,也就是字型庫。下載後將檔案匯入工程,如圖
接著需要在工程配置info.plist中新增這個字型
在info.plist中新增一行,key是Fonts provided by application,中文意思即 字型由應用程式提供
這是個array物件,那麼我們把它展開
往裡面新增一個item,內容即我們剛剛新增的那個檔名
然後在Build Phases裡新增資原始檔 如圖
接下來可以在工程中,通過UIFont 這個類 遍歷我們現在可以用的字型集和字型名字
遍歷程式碼如下
NSArray *fontFamilys = [UIFont familyNames]; for (NSString *familyName infontFamilys) { NSLog(@"family name : %@",familyName); NSArray *fontNames = [UIFont fontNamesForFamilyName:familyName]; for (NSString *fontName in fontNames) { NSLog(@"font name : %@",fontName); } }
注意 ,不同的iOS大版本之間,可使用的字型庫會有差異,但是我們這裡只需要取到我們手動新增的字型
遍歷出來的內容很多,不翻頁也不好找到我們新增的字型。
我這裡新增的字型是微軟雅黑,那麼我搜一下
也是可以找到的,這裡我們需要取font name,即圖上的2016-11-21 09:49:45.780 FontDemo[17853:921926] font name : MicrosoftYaHei
取到字型名字,我們就可以通過
[UIFont fontWithName:@"MicrosoftYaHei" size:16];
fontWithName: size: 這個類方法去得到我們需要的UIFont物件,也就是雅黑字型
------------------------------不華麗的分割線--------------------------
好了,單個字型的更換這裡是實現了,但是我這裡需要的是全域性的字型修改
接下來的內容又要接觸到objc runtime 的method exchange了,也就是method swizzling
在Objective-c中,hook方案能解決很多問題,這裡的問題是其中之一
但是這種全域性設定的方法交換也有一定的侷限性,比如 我需要再換其他字型呢? 這個問題後面再探討
開始設定method swizzling
首先 建立一個UIFont的categroy
在.m檔案中 實現load方法,並呼叫父類load
+ (void)load{ [super load]; }
接著 做method swizzling的過程 只需要呼叫一次,
那麼可以用gcd的once 執行,
+ (void)load{ [super load]; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ Method oldMethod = class_getClassMethod([self class], @selector(systemFontOfSize:)); Method newMethod = class_getClassMethod([self class], @selector(__nickyfontchanger_YaheiFontOfSize:)); method_exchangeImplementations(oldMethod, newMethod); }); }
別忘了#import <objc/runtime.h>
解析一下上面這幾句程式碼
首先Method即方法,class_getClassMethod這是獲取類方法,因為我們原來使用的systemFontOfSize是個類方法。
如果要交換的是例項方法,那麼就要用class_getInstanceMethod 獲取
先獲取舊的方法,再獲取新的方法,新的方法是寫在這個category裡的
像我這裡:
+ (UIFont *)__nickyfontchanger_YaheiFontOfSize:(CGFloat)fontSize{ UIFont *font = [UIFont fontWithName:@"MicrosoftYaHei" size:fontSize]; if (!font)return [self __nickyfontchanger_YaheiFontOfSize:fontSize]; return font; }
再來解析一下這個方法的執行:
首先獲取我們的第三方字型,若字型不存在,則返回系統預設字型
但是為什麼我返回系統預設字型的時候,呼叫的是 [self __nickyfontchanger_YaheiFontOfSize:fontSize]呢?
因為方法已經交換了,實際上這個方法的pointer指向的是系統的systemFontOfSize這個方法
具體的實現
那麼再執行一下工程看看?
ps:問題來了
我要單獨給某個字型設定成系統字型怎麼辦?
事實上我們這裡只是把兩個方法交換了而已,所以我們只要把+ (UIFont *)__nickyfontchanger_YaheiFontOfSize:(CGFloat)fontSize;這個方法寫到.h的聲明裡面即可,它實際就是系統字型
如有錯誤歡迎更正
相關推薦
Objective-C Runtime使用之全域性字型替換為第三方字型(iOS)
前言: iOS開發裡頭,常用的設定字型方式是使用UIFont的systemFontOfSize這個Class Method,在一半情況下都算夠用。 最近有設計師朋友問能不能在客戶端中使用特定的字型,答案是可以的,我們可以通過手動給工程新增配置字型的ttf檔案(字型庫) 然後通過fontWithName:
Objective-C runtime之執行時的基本特點(三)
學了那麼久的Objective-C,給我的感覺就是它什麼都是動態的,你將會聽到一個新的名詞: 一、動態方法解析 1、+(BOOL) resolveInstanceMethod:(SEL) sel 這是NSObject根類提供的類方法,呼叫時機為當被呼叫的方法實現部分沒有找到,而訊息轉發機制啟動之前的這個
Objective-C Runtime 執行時之五:協議與分類
Objective-C中的分類允許我們通過給一個類新增方法來擴充它(但是通過category不能新增新的例項變數),並且我們不需要訪問類中的程式碼就可以做到。 Objective-C中的協議是普遍存在的介面定義方式,即在一個類中通過@protocol定義介面,在另外
Objective-C Runtime 執行時之六:拾遺
前面幾篇基本介紹了runtime中的大部分功能,包括對類與物件、成員變數與屬性、方法與訊息、分類與協議的處理。runtime大部分的功能都是圍繞這幾點來實現的。 本章的內容並不算重點,主要針對前文中對Objective-C Runtime Reference內容遺漏
Objective-C Runtime 執行時之二:成員變數與屬性
在前面一篇文章中,我們介紹了Runtime中與類和物件相關的內容,從這章開始,我們將討論類實現細節相關的內容,主要包括類中成員變數,屬性,方法,協議與分類的實現。 本章的主要內容將聚集在Runtime對成員變數與屬性的處理。在討論之前,我們先介紹一個重要的概念:型別
Objective-C Runtime 執行時之三:方法與訊息
前面我們討論了Runtime中對類和物件的處理,及對成員變數與屬性的處理。這一章,我們就要開始討論Runtime中最有意思的一部分:訊息處理機制。我們將詳細討論訊息的傳送及訊息的轉發。不過在討論訊息之前,我們先來了解一下與方法相關的一些內容。 基礎資料型別 SEL
Objective-C Runtime 執行時之四:Method Swizzling
理解Method Swizzling是學習runtime機制的一個很好的機會。在此不多做整理,僅翻譯由Mattt Thompson發表於nshipster的Method Swizzling一文。 Method Swizzling是改變一個selector的實際實現的
Objective-C runtime原始碼學習之IMP定址(不包括訊息轉發部分)
寫在前面 前段時間寫了一篇部落格runtime如何通過selector找到對應的IMP地址?(分別考慮類方法和例項方法),這是在看《招聘一個靠譜的iOS》時回答第22題時總結的一篇部落格,不過這篇部落格中並沒有牽涉到底層的程式碼,而且也留下了幾個沒有解決的
iOS學習筆記56(Runtime)-Objective-C Runtime 執行時之三:方法與訊息
前面我們討論了Runtime中對類和物件的處理,及對成員變數與屬性的處理。這一章,我們就要開始討論Runtime中最有意思的一部分:訊息處理機制。我們將詳細討論訊息的傳送及訊息的轉發。不過在討論訊息之前,我們先來了解一下與方法相關的一些內容。 基礎資料型別 SEL
objective-c runtime安全措施之二:反注入
《O'Reilly.Hacking.and.Securing.iOS.Applications>>讀書筆記 反注入:在類函式被呼叫前做完整性檢測(預防應用自定義函式或apple標準庫函式被修改或替換) 原理:呼叫dladdr()函式檢查類方法的基本資訊是否合法
OBJECTIVE-C學習之宏定義
list com 學習 c學習 ive 宏定義 objective cti lis %E6%B5%85%E8%B0%88aNDROID%E7%89%88%E6%9C%AC%E7%9A%84%E5%8C%BA%E5%88%AB http://music.baidu.com/
Objective-C Runtime 文檔翻譯(一)—Runtime版本和平臺
註意 mar 包含 mark 編譯 href enc 文檔翻譯 需要 前言 ? 在不同的平臺,有不同版本的OC runtime。 ? 舊的和現在的版本 ? 有兩個版本的OC runtime——“舊版”和“現在版”。現在版就是OC-2.0並包含了許多新特性。舊版本的ru
Objective-C 基礎之— Block本質+源碼剖析
www IT -s 猜想 field char 源碼 等等 eof block 又稱之為“自帶變量的匿名函數”,拋開OC語法定義block的形式不談,其實好多語言都有類似的函數,比如JS的回調函數(其實就是將一個匿名還是作為函數的實參)、swift的閉
Objective-C基礎之@synthesize, @dynamic
not getter var 實例 利用 基礎 PE category protoc Objective-C基礎之@synthesize, @dynamic OC屬性用一個表達式最能清楚的解釋其實質:property = ivar + setter+getter,也就是說一
Objective-C runtime機制
Objective-C runtime機制 先來看看怎麼理解發送訊息的含義: 曾經覺得Objc特別方便上手,面對著 Cocoa 中大量 API,只知道簡單的查文件和呼叫。還記得初學 Objective-C 時把[receiver message]當成簡單的方法呼叫,而無視了“傳送訊息
Objective-C runtime機制(7)——SideTables, SideTable, weak_table, weak_entry_t
在runtime中,有四個資料結構非常重要,分別是SideTables,SideTable,weak_table_t和weak_entry_t。它們和物件的引用計數,以及weak引用相關。 關係 先說一下這四個資料結構的關係。 在runtime記憶體空間中,SideTables是
Objective-C runtime機制(6)——weak引用的底層實現原理
前言 提起弱引用,大家都知道它的作用: (1)不會新增引用計數 (2)當所引用的物件釋放後,引用者的指標自動置為nil 那麼,圍繞它背後的實現,是怎麼樣的呢?在許多公司面試時,都會問到這個問題。那麼,今天就帶大家一起分析一下weak引用是怎麼實現的,希望能夠搞清楚每一個細節。 S
Objective-C runtime機制(5)——iOS 記憶體管理
概述 當我們建立一個物件時: SWHunter *hunter = [[SWHunter alloc] init]; 上面這行程式碼在棧上建立了hunter指標,並在堆上建立了一個SWHunter物件。目前,iOS並不支援在棧上建立物件。 iOS 記憶體分割槽 iOS
Objective-C runtime機制(4)——深入理解Category
在平日程式設計中或閱讀第三方程式碼時,category可以說是無處不在。category也可以說是OC作為一門動態語言的一大特色。category為我們動態擴充套件類的功能提供了可能,或者我們也可以把一個龐大的類進行功能分解,按照category進行組織。 關於category的使用
Objective-C runtime機制(3)——method swizzling
方法替換,又稱為method swizzling,是一個比較著名的runtime黑魔法。網上有很多的實現,我們這裡直接講最正規的實現方式以及其背後的原理。 Method Swizzling 在進行方法替換前,我們要考慮兩種情況: 要替換的方法在target class