Runtime常規用法示例

    不論是在面試過程中,還是自己開發項目遇到問題時,runtime經常能解決一些常規情況下遇到的難以解決的部分。    
    今天閱讀過一篇關于runtime常規用法的文章,覺得不錯便想要通過簡化原有文章進行知識存儲。   
    文章參考出處:http://www.cnblogs.com/ludashi/p/6294112.html    
    文章參考作者:青玉伏案

    本篇主要講述了以下幾種runtime用法,有一定基礎用于提醒自己的玩家可以直接看表格,其他玩家請繼續往下看:
用法 關鍵函數
動態獲取類名 const char *class_getName(Class cls)
動態獲取類的成員變量 Ivar *class_copyIvarList(Class cls, unsigned int *outCount)、<br />const char *ivar_getName(Ivar v)、<br />const char *ivar_getTypeEncoding(Ivar v)
動態獲取類的屬性列表 objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)、<br />const char *property_getName(objc_property_t property)
動態獲取類的實例方法列表 Method *class_copyMethodList(Class cls, unsigned int *outCount)、<br />SEL method_getName(Method m)
動態獲取類所遵循的協議列表 Protocol * __unsafe_unretained *class_copyProtocolList(Class cls, unsigned int *outCount)、<br />const char *protocol_getName(Protocol *p)
動態添加新的方法 Method class_getInstanceMethod(Class cls, SEL name)、<br />IMP method_getImplementation(Method m)、<br />const char *method_getTypeEncoding(Method m)、<br />BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
類的實例方法實現交換 Method class_getInstanceMethod(Class cls, SEL name)、<br />void method_exchangeImplementations(Method m1, Method m2)
動態屬性關聯 void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)、<br />id objc_getAssociatedObject(id object, const void *key)
消息發送與消息轉發機制 + (BOOL)resolveInstanceMethod:(SEL)sel、<br />- (id)forwardingTargetForSelector:(SEL)aSelector、<br />- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector、<br />- (void)forwardInvocation:(NSInvocation *)anInvocation

    我們首先封裝一個測試類TestClass,其中需要包含遵守協議,并添加公有屬性、私有屬性、私有成員變量、公有實例方法、私有實例方法、類方法等。    
    這些內容的添加主要便于之后的測試。
TestClass方法變量聲明.png
TestClass私有變量.png
TestClass方法實現.png

一、動態獲悉類結構

1. 動態獲取類名

    采用`class_getName(cls)`在運行時獲取類的名稱。將char類型的指針轉換成NSString類型進行返回。
獲取類名.png

2. 動態獲取成員變量

    采用`class_copyIvarList(cls, count)`獲取成員變量列表。使用`ivar_getName(variable)`來輸出成員變量名稱,`ivar_getTypeEncoding(variable)`來輸出成員變量類型。    
    我們通過將所得數據組合成NSDictionary來存儲單個變量,若干個字典組成NSArray作為屬性列表的返回。
獲取成員變量.png
    使用TestClass進行用例測試。由于是調用上述方法獲取TestClass的成員變量,到了運行時階段實際就不存在公有私有之分。OC中的類在ARC情況下添加的屬性,其實就是自動生成其get方法與set方法。    
    所有獲取的成員列表中肯定帶有成員屬性,成員屬性的名稱前方帶有下劃線用于成員變量進行區分。    
    下方中各基本類型由特殊字母代替,可以看出i代表int類型,c代表bool類型,d表示double類型,f表示float類型。而如果是引用類型則直接是一個字符串顯示,比如NSString類型就是@"NSString"。
測試成員列表打印.png

3. 動態獲取成員屬性列表

    上方獲取了類的成員變量,那么下方進行屬性列表的獲取。屬性區分于變量主要是它們擁有完整的set方法和get方法。    
    我們使用`class_copyPropertyList(cls, count)`來獲取屬性列表,通過`property_getName(property)`來獲取屬性名稱。
獲取屬性列表.png
    下方dynamic的屬性是我們使用runtime進行動態添加的。
測試屬性列表打印.png

4. 獲取類的實例方法

    我們通過`class_copyMethodList(cls, count)`來獲取實例方法列表,通過`method_getName(method)`來獲取實例方法名稱。
獲取實例方法.png
    下方打印了所有TestClass類的實例方法,當然包括成員屬性的set方法和get方法。**其中`.cxx_destruct`方法不確認歸屬于何處,也許dealloc方法的自我實現?**
測試實例方法列表打印.png

5. 獲取類的協議列表

    我們使用`class_copyProtocolList(cls, count)`來獲取協議列表,使用`protocol_getName(protocol)`來獲取協議名稱
獲取協議列表.png

二、動態操作類方法

1. 動態添加方法實現

    其添加原理旨在使用`class_getInstanceMethod(cls, methodName)`獲取相關的方法聲明以及使用`method_getImplementation(method)`獲取相關的方法實現。將它們進行組合后,使用`class_addMethod(cls, methodName, method, type)`進行方法的添加。
動態添加方法實現.png

2. 實現方法交換

    通過`class_getInstanceMethod(cls, methodName)`獲取到需要交換的兩個方法,直接使用`method_exchangeImplementation(methodA, methodB)`進行方法替換即可。
實現方法交換.png
    通過類目為測試類封裝一個針對交換方法的測試用例。
  • 如果是普通情況下,沒有交換。在replaceMethod中調用本身勢必會造成死循環。
  • 如是如果交換方法成功,那么此時在replaceMethod中調用replaceMethod,其實此時調用的是exchangeMethodA。由于exchangeMethodA不存在死循環,故在測試時,調用了封裝的交換方法后,進一步又調用了replaceMethod,其實只是調用了exchangeMethodA而已。
    交換方法的封裝.png

三、屬性關聯

    屬性關聯可以說是runtime最普通的打開方式了。通過為屬性聲明一個靜態名稱,調用`void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)`實現新增屬性的set方法,調用`id objc_getAssociatedObject(id object, const void *key)`實現新增屬性的get方法即可。
動態添加屬性.png

四、消息處理與消息轉發

  • 消息處理過程:
  • 當你調用一個類的方法時,先在本類中的方法緩存列表中進行查詢,如果在緩存列表中找到了該方法的實現,就執行;如果找不到就在本類中的方法列表中進行查找。
  • 在本類方法列表中查找到相應的方法實現后就進行調用,如果沒找到,就去父類中進行查找;如果在父類中的方法列表中找到了相應方法的實現。

當在方法緩存列表,本類中的方法列表以及父類中的方法列表中都找不到相應的實現,到程序崩潰以前還會經歷以下過程:

  1. 消息處理
  • 如果一直尋找方法直到父類中都找不到方法實現時會執行+ (BOOL)resolveInstanceMethod:(SEL)sel類方法。
  • 如果返回NO,則表明不做任何處理,繼續下一步。如果返回YES,就說明該方法中對找不到實現的方法進行了處理。
  • 我們就可以在此方法中為找不到實現的SEL動態添加一個方法實現,添加完畢后,就會執行我們添加的方法實現。
  • 下一次程序再找不到該類某個方法的實現時,就不會因為找不到而崩潰了。
消息處理.png

2.消息轉發

  • 如果不對上述消息進行處理的話,也就是+ (BOOL)resolveInstanceMethod:(SEL)sel方法返回NO時。便進入了下一步消息轉發。
  • 即執行- (id)forwardingTargetForSelector:(SEL)aSelector方法。該方法會返回一個類對象,該類的對象有SEL對應的實現,當調用這個找不到方法時,就會轉發到ExtClass中進行處理。
  • 此時完成消息轉發。如果該方法返回self或者nil,說明不對相應的方法進行轉發,那就再走下一步。
消息轉發.png

3.消息常規轉發

  • 如果不將消息轉發給其他類的對象,則此時代表自己進行處理。即上述的方法中返回self或者nil。
  • 此時執行- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector來獲取方法的參數以及返回數據類型,即可以理解為該方法的簽名。

  • 如果此時再次返回nil,那么消息轉發結束。程序崩潰,報出找不到相應的方法實現的崩潰消息。

  • 下方方法執行的先決條件,是要在+ (BOOL)resolveInstanceMethod:(SEL)sel中返回NO。然后下方也是進行將方法轉給ExtClass的實現。

消息常規轉發.png
    本文項目Github鏈接地址:https://github.com/LibertyLeo/Runtime-Usage
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,001評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,786評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,986評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,204評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,964評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,354評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,410評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,554評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,106評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,918評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,093評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,648評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,342評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,755評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,009評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,839評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,107評論 2 375

推薦閱讀更多精彩內容

  • 轉至元數據結尾創建: 董瀟偉,最新修改于: 十二月 23, 2016 轉至元數據起始第一章:isa和Class一....
    40c0490e5268閱讀 1,753評論 0 9
  • 我們常常會聽說 Objective-C 是一門動態語言,那么這個「動態」表現在哪呢?我想最主要的表現就是 Obje...
    Ethan_Struggle閱讀 2,227評論 0 7
  • 原文出處:南峰子的技術博客 Objective-C語言是一門動態語言,它將很多靜態語言在編譯和鏈接時期做的事放到了...
    _燴面_閱讀 1,246評論 1 5
  • 這篇文章完全是基于南峰子老師博客的轉載 這篇文章完全是基于南峰子老師博客的轉載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,579評論 33 466
  • 第九十二課 背景顏色 1、如何設置標簽的背景顏色在CSS中有一個background-color:屬性,就是專門用...
    S大偉閱讀 264評論 0 0