如有轉(zhuǎn)載,請(qǐng)標(biāo)明出處:iOS runtime如何交換兩個(gè)類方法
runtime交換實(shí)例方法隧饼,老生常談的問題,很多blog都有介紹過诞丽,但是好像暫時(shí)沒有找到過如何交換兩個(gè)類的類方法。通過對(duì)元類的學(xué)習(xí)刑赶,作者自行摸索懂衩,終于嘗試出如何交換兩個(gè)類方法。元類的具體內(nèi)容谒所,見《類對(duì)象沛申、元類》一章。
實(shí)例方法的交換:
void class_swizzleInstanceMethod(Class class, SEL originalSEL, SEL replacementSEL)
{
//class_getInstanceMethod()尖淘,如果子類沒有實(shí)現(xiàn)相應(yīng)的方法,則會(huì)返回父類的方法村生。
Method originMethod = class_getInstanceMethod(class, originalSEL);
Method replaceMethod = class_getInstanceMethod(class, replacementSEL);
//class_addMethod() 判斷originalSEL是否在子類中實(shí)現(xiàn)饼丘,如果只是繼承了父類的方法,沒有重寫肄鸽,那么直接調(diào)用method_exchangeImplementations,則會(huì)交換父類中的方法和當(dāng)前的實(shí)現(xiàn)方法典徘。此時(shí)如果用父類調(diào)用originalSEL,因?yàn)榉椒ㄒ呀?jīng)與子類中調(diào)換帜平,所以父類中找不到相應(yīng)的實(shí)現(xiàn)梅鹦,會(huì)拋出異常unrecognized selector.
//當(dāng)class_addMethod() 返回YES時(shí),說明子類未實(shí)現(xiàn)此方法(根據(jù)SEL判斷)齐唆,此時(shí)class_addMethod會(huì)添加(名字為originalSEL,實(shí)現(xiàn)為replaceMethod)的方法蝶念。此時(shí)在將replacementSEL的實(shí)現(xiàn)替換為originMethod的實(shí)現(xiàn)即可芋绸。
//當(dāng)class_addMethod() 返回NO時(shí)担敌,說明子類中有該實(shí)現(xiàn)方法,此時(shí)直接調(diào)用method_exchangeImplementations交換兩個(gè)方法的實(shí)現(xiàn)即可全封。
//注:如果在子類中實(shí)現(xiàn)此方法了马昙,即使只是單純的調(diào)用super刹悴,一樣算重寫了父類的方法,所以class_addMethod() 會(huì)返回NO子房。
//可用BaseClass實(shí)驗(yàn)
if(class_addMethod(class, originalSEL, method_getImplementation(replaceMethod),method_getTypeEncoding(replaceMethod)))
{
class_replaceMethod(class,replacementSEL, method_getImplementation(originMethod), method_getTypeEncoding(originMethod));
}else {
method_exchangeImplementations(originMethod, replaceMethod);
}
}
通過如上代碼就轧,傳入相應(yīng)的Class及selector,即可交換對(duì)應(yīng)的方法妒御。
類方法的交換:
通過對(duì)元類的學(xué)習(xí),我們可以知道乎莉,其實(shí)Class(也就是類)本身也是一個(gè)對(duì)象,他的類可以通過object_getClass(class)
方法得到哼鬓,這種類對(duì)象的類就叫做元類。所以一個(gè)類的類方法魄宏,也就是其元類的實(shí)例方法存筏,我們可以通過將其元類傳入味榛,即可交互類方法椭坚。
void class_swizzleClassMethod(Class class, SEL originalSEL, SEL replacementSEL)
{
//類方法實(shí)際上是儲(chǔ)存在類對(duì)象的類(即元類)中搏色,即類方法相當(dāng)于元類的實(shí)例方法,所以只需要把元類傳入,其他邏輯和交互實(shí)例方法一樣垂涯。
Class class2 = object_getClass(class);
class_swizzleInstanceMethod(class2, originalSEL, replacementSEL);
}
雖然代碼很容易,但是里面的原理并不是很簡(jiǎn)單耕赘。
附上demo