上篇我們講到了runtime 的動態(tài)添加屬性和方法,遍歷對象的屬性列表,今天我們來講一下runtime里面更好用的東西 - 方法交換。
在OC里面,一個方法的基礎(chǔ)對象是objc_method
,他的組成結(jié)構(gòu)如下
一個objc_method 里面包含著 一個SEL(方法名),method_types,和一個method_imp(方法實現(xiàn)的指針),method_imp是一個方法對象里最重要的,它指向該方法實現(xiàn)的地址,所以我們平時看到的方法名,它其實不是一個真正的實現(xiàn)者,可以看作是一個方法唯一的標(biāo)示。
接下來我們要講的方法交換,其實就是交換方法實現(xiàn)的指針。我們來看一下runtime里面相關(guān)的API:
SEL method_getName(Method m)? //獲取方法名
IMP method_getImplementation(Method m)//獲取方法的指針
?int method_getNumberOfArguments(Method m)//獲取方法的參數(shù)個數(shù)
char *method_copyReturnType(Method m)//獲取方法返回值的類型
char *method_copyArgumentType(Method m, unsigned int index)//某個參數(shù)的類型
IMP method_setImplementation(Method m, IMP imp)//設(shè)置方法的指針(替換方法實現(xiàn))
method_exchangeImplementations(Method m1, Method m2)//交換方法的指針(交換方法實現(xiàn))
其中,對指針的操作是方法交換的核心內(nèi)容,用 method_setImplementation 可以進(jìn)行方法的替換,用method_exchangeImplementations就可以完成交換 其用法如下,
例子1:
方法替換
在圖二中,我在UIImage的分類里將imageNamed:的IMP替換成自己寫的replaceImage,所以在圖3的實現(xiàn)中,我調(diào)用imageNamed:的時候,程序就跑到了我我新替換的指針方法實現(xiàn)。
例2:
方法交換
圖4我們用method_exchangeImplementations 將兩個方法的IMP進(jìn)行了互換,當(dāng)我調(diào)用imageNamed:的時候,系統(tǒng)根據(jù)imageNamed
:里現(xiàn)有的IMP(已被替換成imageWithName:)去找到執(zhí)行的地址,當(dāng)我在return 時執(zhí)行[self imageWithName:name]方法的時候,系統(tǒng)也會根據(jù)該方法的IMP去找到相應(yīng)要執(zhí)行的地址。因為imageWithName的IMP已經(jīng)被替換了,所以我執(zhí)行 return [self imageWithName:name]并不會產(chǎn)生死循環(huán)。
說了那么多,方法交換究竟有什么用????
主要用途:批量修改(重定向),數(shù)組臨界值的問題,UIViewController生命周期的調(diào)取
1.批量修改,如上面的例2,該如我需要新增一個換膚系統(tǒng),就可以用imageWithName
替換原生的imageName,這樣在不改變其他代碼的情況下,完成資源的切換。
2.數(shù)組臨界值的問題,突入其來的數(shù)據(jù)越界讓你的措手不及有沒有?解決方法如下
例子3:
在NSarray類別中,新建方法securityObjectAtIndex:,并讓他與NSarray的 方法objectAtIndex:交換指針
//臨界值
*方法的交換我就講到這里,下篇我們講解如何避免 unrecognized selector sent to instance (找不到對象/方法)