Runtime 知識(shí)整理

一瓢谢、如何在項(xiàng)目中使用runtime

第一步: 在需要使用的類(lèi)中導(dǎo)入文件

#import

第二步: 在Build Setting中搜索msg,

二呛牲、本篇主要講述了以下幾種runtime用法,有一定基礎(chǔ)用于提醒自己的玩家可以直接看表格,其他玩家請(qǐng)繼續(xù)往下看:

用法關(guān)鍵函數(shù)

動(dòng)態(tài)獲取類(lèi)名const char *class_getName(Class cls)

動(dòng)態(tài)獲取類(lèi)的成員變量Ivar *class_copyIvarList(Class cls, unsigned int *outCount)韩容、

const char *ivar_getName(Ivar v)扣唱、

const char *ivar_getTypeEncoding(Ivar v)

動(dòng)態(tài)獲取類(lèi)的屬性列表objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)藕坯、

const char *property_getName(objc_property_t property)

動(dòng)態(tài)獲取類(lèi)的實(shí)例方法列表Method *class_copyMethodList(Class cls, unsigned int *outCount)、

SEL method_getName(Method m)

動(dòng)態(tài)獲取類(lèi)所遵循的協(xié)議列表Protocol * __unsafe_unretained *class_copyProtocolList(Class cls, unsigned int *outCount)噪沙、

const char *protocol_getName(Protocol *p)

動(dòng)態(tài)添加新的方法Method class_getInstanceMethod(Class cls, SEL name)炼彪、

IMP method_getImplementation(Method m)、

const char *method_getTypeEncoding(Method m)正歼、

BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)

類(lèi)的實(shí)例方法實(shí)現(xiàn)交換Method class_getInstanceMethod(Class cls, SEL name)辐马、

void method_exchangeImplementations(Method m1, Method m2)

動(dòng)態(tài)屬性關(guān)聯(lián)void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)、

id objc_getAssociatedObject(id object, const void *key)

消息發(fā)送與消息轉(zhuǎn)發(fā)機(jī)制+ (BOOL)resolveInstanceMethod:(SEL)sel局义、

- (id)forwardingTargetForSelector:(SEL)aSelector喜爷、

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector、

- (void)forwardInvocation:(NSInvocation *)anInvocation

我們首先封裝一個(gè)測(cè)試類(lèi)TestClass萄唇,其中需要包含遵守協(xié)議檩帐,并添加公有屬性、私有屬性另萤、私有成員變量湃密、公有實(shí)例方法、私有實(shí)例方法、類(lèi)方法等泛源。

這些內(nèi)容的添加主要便于之后的測(cè)試拔妥。

TestClass方法變量聲明.png

TestClass私有變量.png

TestClass方法實(shí)現(xiàn).png

一、動(dòng)態(tài)獲悉類(lèi)結(jié)構(gòu)

1. 動(dòng)態(tài)獲取類(lèi)名

采用class_getName(cls)在運(yùn)行時(shí)獲取類(lèi)的名稱(chēng)俩由。將char類(lèi)型的指針轉(zhuǎn)換成NSString類(lèi)型進(jìn)行返回毒嫡。

獲取類(lèi)名.png

2. 動(dòng)態(tài)獲取成員變量

采用class_copyIvarList(cls, count)獲取成員變量列表。使用ivar_getName(variable)來(lái)輸出成員變量名稱(chēng)幻梯,ivar_getTypeEncoding(variable)來(lái)輸出成員變量類(lèi)型兜畸。

我們通過(guò)將所得數(shù)據(jù)組合成NSDictionary來(lái)存儲(chǔ)單個(gè)變量,若干個(gè)字典組成NSArray作為屬性列表的返回碘梢。

獲取成員變量.png

使用TestClass進(jìn)行用例測(cè)試咬摇。由于是調(diào)用上述方法獲取TestClass的成員變量,到了運(yùn)行時(shí)階段實(shí)際就不存在公有私有之分煞躬。OC中的類(lèi)在ARC情況下添加的屬性肛鹏,其實(shí)就是自動(dòng)生成其get方法與set方法。

所有獲取的成員列表中肯定帶有成員屬性恩沛,成員屬性的名稱(chēng)前方帶有下劃線(xiàn)用于成員變量進(jìn)行區(qū)分在扰。

下方中各基本類(lèi)型由特殊字母代替,可以看出i代表int類(lèi)型雷客,c代表bool類(lèi)型芒珠,d表示double類(lèi)型,f表示float類(lèi)型搅裙。而如果是引用類(lèi)型則直接是一個(gè)字符串顯示皱卓,比如NSString類(lèi)型就是@"NSString"。

測(cè)試成員列表打印.png

3. 動(dòng)態(tài)獲取成員屬性列表

上方獲取了類(lèi)的成員變量部逮,那么下方進(jìn)行屬性列表的獲取娜汁。屬性區(qū)分于變量主要是它們擁有完整的set方法和get方法。

我們使用class_copyPropertyList(cls, count)來(lái)獲取屬性列表兄朋,通過(guò)property_getName(property)來(lái)獲取屬性名稱(chēng)掐禁。

獲取屬性列表.png

下方dynamic的屬性是我們使用runtime進(jìn)行動(dòng)態(tài)添加的。

測(cè)試屬性列表打印.png

4. 獲取類(lèi)的實(shí)例方法

我們通過(guò)class_copyMethodList(cls, count)來(lái)獲取實(shí)例方法列表蜈漓,通過(guò)method_getName(method)來(lái)獲取實(shí)例方法名稱(chēng)穆桂。

獲取實(shí)例方法.png

下方打印了所有TestClass類(lèi)的實(shí)例方法,當(dāng)然包括成員屬性的set方法和get方法融虽。其中.cxx_destruct方法不確認(rèn)歸屬于何處享完,也許dealloc方法的自我實(shí)現(xiàn)?

測(cè)試實(shí)例方法列表打印.png

5. 獲取類(lèi)的協(xié)議列表

我們使用class_copyProtocolList(cls, count)來(lái)獲取協(xié)議列表有额,使用protocol_getName(protocol)來(lái)獲取協(xié)議名稱(chēng)

獲取協(xié)議列表.png

二般又、動(dòng)態(tài)操作類(lèi)方法

1. 動(dòng)態(tài)添加方法實(shí)現(xiàn)

其添加原理旨在使用class_getInstanceMethod(cls, methodName)獲取相關(guān)的方法聲明以及使用method_getImplementation(method)獲取相關(guān)的方法實(shí)現(xiàn)彼绷。將它們進(jìn)行組合后,使用class_addMethod(cls, methodName, method, type)進(jìn)行方法的添加茴迁。

動(dòng)態(tài)添加方法實(shí)現(xiàn).png

2. 實(shí)現(xiàn)方法交換

通過(guò)class_getInstanceMethod(cls, methodName)獲取到需要交換的兩個(gè)方法寄悯,直接使用method_exchangeImplementation(methodA, methodB)進(jìn)行方法替換即可。

實(shí)現(xiàn)方法交換.png

通過(guò)類(lèi)目為測(cè)試類(lèi)封裝一個(gè)針對(duì)交換方法的測(cè)試用例堕义。

如果是普通情況下猜旬,沒(méi)有交換。在replaceMethod中調(diào)用本身勢(shì)必會(huì)造成死循環(huán)倦卖。

如是如果交換方法成功洒擦,那么此時(shí)在replaceMethod中調(diào)用replaceMethod,其實(shí)此時(shí)調(diào)用的是exchangeMethodA怕膛。由于exchangeMethodA不存在死循環(huán)熟嫩,故在測(cè)試時(shí),調(diào)用了封裝的交換方法后褐捻,進(jìn)一步又調(diào)用了replaceMethod掸茅,其實(shí)只是調(diào)用了exchangeMethodA而已。

交換方法的封裝.png

三柠逞、屬性關(guān)聯(lián)

屬性關(guān)聯(lián)可以說(shuō)是runtime最普通的打開(kāi)方式了昧狮。通過(guò)為屬性聲明一個(gè)靜態(tài)名稱(chēng),調(diào)用void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)實(shí)現(xiàn)新增屬性的set方法板壮,調(diào)用id objc_getAssociatedObject(id object, const void *key)實(shí)現(xiàn)新增屬性的get方法即可陵且。

動(dòng)態(tài)添加屬性.png

四、消息處理與消息轉(zhuǎn)發(fā)

消息處理過(guò)程:

當(dāng)你調(diào)用一個(gè)類(lèi)的方法時(shí)个束,先在本類(lèi)中的方法緩存列表中進(jìn)行查詢(xún),如果在緩存列表中找到了該方法的實(shí)現(xiàn)聊疲,就執(zhí)行茬底;如果找不到就在本類(lèi)中的方法列表中進(jìn)行查找。

在本類(lèi)方法列表中查找到相應(yīng)的方法實(shí)現(xiàn)后就進(jìn)行調(diào)用获洲,如果沒(méi)找到阱表,就去父類(lèi)中進(jìn)行查找;如果在父類(lèi)中的方法列表中找到了相應(yīng)方法的實(shí)現(xiàn)贡珊。

當(dāng)在方法緩存列表最爬,本類(lèi)中的方法列表以及父類(lèi)中的方法列表中都找不到相應(yīng)的實(shí)現(xiàn),到程序崩潰以前還會(huì)經(jīng)歷以下過(guò)程:

消息處理

如果一直尋找方法直到父類(lèi)中都找不到方法實(shí)現(xiàn)時(shí)會(huì)執(zhí)行+ (BOOL)resolveInstanceMethod:(SEL)sel類(lèi)方法门岔。

如果返回NO爱致,則表明不做任何處理,繼續(xù)下一步寒随。如果返回YES糠悯,就說(shuō)明該方法中對(duì)找不到實(shí)現(xiàn)的方法進(jìn)行了處理帮坚。

我們就可以在此方法中為找不到實(shí)現(xiàn)的SEL動(dòng)態(tài)添加一個(gè)方法實(shí)現(xiàn),添加完畢后互艾,就會(huì)執(zhí)行我們添加的方法實(shí)現(xiàn)试和。

下一次程序再找不到該類(lèi)某個(gè)方法的實(shí)現(xiàn)時(shí),就不會(huì)因?yàn)檎也坏蕉罎⒘恕?/p>

消息處理.png

2.消息轉(zhuǎn)發(fā)

如果不對(duì)上述消息進(jìn)行處理的話(huà)纫普,也就是+ (BOOL)resolveInstanceMethod:(SEL)sel方法返回NO時(shí)阅悍。便進(jìn)入了下一步消息轉(zhuǎn)發(fā)。

即執(zhí)行- (id)forwardingTargetForSelector:(SEL)aSelector方法昨稼。該方法會(huì)返回一個(gè)類(lèi)對(duì)象节视,該類(lèi)的對(duì)象有SEL對(duì)應(yīng)的實(shí)現(xiàn),當(dāng)調(diào)用這個(gè)找不到方法時(shí)悦昵,就會(huì)轉(zhuǎn)發(fā)到ExtClass中進(jìn)行處理肴茄。

此時(shí)完成消息轉(zhuǎn)發(fā)。如果該方法返回self或者nil但指,說(shuō)明不對(duì)相應(yīng)的方法進(jìn)行轉(zhuǎn)發(fā)寡痰,那就再走下一步。

消息轉(zhuǎn)發(fā).png

3.消息常規(guī)轉(zhuǎn)發(fā)

如果不將消息轉(zhuǎn)發(fā)給其他類(lèi)的對(duì)象棋凳,則此時(shí)代表自己進(jìn)行處理拦坠。即上述的方法中返回self或者nil。

此時(shí)執(zhí)行- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector來(lái)獲取方法的參數(shù)以及返回?cái)?shù)據(jù)類(lèi)型剩岳,即可以理解為該方法的簽名贞滨。

如果此時(shí)再次返回nil,那么消息轉(zhuǎn)發(fā)結(jié)束拍棕。程序崩潰晓铆,報(bào)出找不到相應(yīng)的方法實(shí)現(xiàn)的崩潰消息。

下方方法執(zhí)行的先決條件绰播,是要在+ (BOOL)resolveInstanceMethod:(SEL)sel中返回NO骄噪。然后下方也是進(jìn)行將方法轉(zhuǎn)給ExtClass的實(shí)現(xiàn)。

消息常規(guī)轉(zhuǎn)發(fā).png

本文項(xiàng)目Github鏈接地址:https://github.com/LibertyLeo/Runtime-Usage

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蠢箩,一起剝皮案震驚了整個(gè)濱河市链蕊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌谬泌,老刑警劉巖滔韵,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異掌实,居然都是意外死亡陪蜻,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)潮峦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)囱皿,“玉大人勇婴,你說(shuō)我怎么就攤上這事≈鲂龋” “怎么了耕渴?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)齿兔。 經(jīng)常有香客問(wèn)我橱脸,道長(zhǎng),這世上最難降的妖魔是什么分苇? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任添诉,我火速辦了婚禮,結(jié)果婚禮上医寿,老公的妹妹穿的比我還像新娘栏赴。我一直安慰自己,他們只是感情好靖秩,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布须眷。 她就那樣靜靜地躺著,像睡著了一般沟突。 火紅的嫁衣襯著肌膚如雪花颗。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,079評(píng)論 1 285
  • 那天惠拭,我揣著相機(jī)與錄音扩劝,去河邊找鬼。 笑死职辅,一個(gè)胖子當(dāng)著我的面吹牛棒呛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播域携,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼条霜,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了涵亏?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蒲凶,失蹤者是張志新(化名)和其女友劉穎气筋,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體旋圆,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡宠默,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了灵巧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片搀矫。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡抹沪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出瓤球,到底是詐尸還是另有隱情融欧,我是刑警寧澤,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布卦羡,位于F島的核電站噪馏,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏绿饵。R本人自食惡果不足惜欠肾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望拟赊。 院中可真熱鬧刺桃,春花似錦、人聲如沸吸祟。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)欢搜。三九已至封豪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間炒瘟,已是汗流浹背吹埠。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留疮装,地道東北人缘琅。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像廓推,于是被迫代替她去往敵國(guó)和親刷袍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

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