(方法調配)Method Swizzling,methodswizzling
一、概念
方法調配:因為Objective-C是運行時語言,也就是說究竟會調用何種方法要在運行期才能解析出來。那麼我們其實也可以在運行時改變選擇子名稱。這樣我們既不需要查看到原始碼,又沒有必要去重寫子類來覆寫方法就能改變類本身的功能。這樣一來新功能就會在類的所有執行個體中表現出來,而不僅限於那些重寫子類的執行個體。這種方案就叫做“方法調配”(method swizzling)。
IMP:類方法列表會把選擇子的名稱映射到方法的實現上,使得動態訊息派發系統能夠據次找到應該調用的方法,這些方法均以指標的形式來表示,這種指標叫做IMP。其原型如下:
id(* IMP)(id,SEL,.....)
SEL:選取器用於表示一個方法在運行時的名字,一個方法的選取器是一個註冊到(或映射到)Objective-C運行時中的C字串,它是由編譯器產生並在類載入的時候被運行時系統自動對應。
一個類(Class)維護一張調度表(dispatch table)用於解析運行時發送的訊息;調度表中的每個實體(entry)都是一個方法(Method),其中key值是一個唯一的名字——選取器(SEL),它對應到一個實現(IMP)——實際上就是指向標準C函數的指標。
二、方法調配的實現
首先看兩張圖片:
以2-3是NSString可以相應的選擇子lowercaseString,uppercaseString,capitalizedString。每個選擇子都映射到了不同的IMP。現在我們通過運行系統提供的方法來將選擇子映射表改為2-4所示的映射表。
先簡單說一下:我們沒有重寫子類或者其他,而是修改了方法的布局,這樣就會反映到所有的NSString執行個體上。以下是一些基本的函數操作以及作用:
①、交換方法的實現
void method_exchangeImplementations(Method m1,Method m2)
此方法的參數是兩個方法實現,方法實現可以通過以下函數獲得:
Method class_getInstanceMethod(Class class,SEL aSelector)
次方法根據給定的選擇從類中取出相應的方法。現在舉個例子交換lowcaseString和uppercaseString:
Method originMethod = class_getInstanceMethod([NSString class],@selector(lowcaseString));Method swipMethod = class_getInstanceMethod([NSString class],@selector(uppercaseString));method_exchangeImplementations(originMethod,swipMethod);
此時如果我們調用NSString的lowcaseString那麼實現的結果是uppercaseString的實現。(即如果調用小寫轉換則是大寫轉換)。
直接交換的意義不大,我們一般都會用在想重寫一個類的方法,然後添加自己的東西,然後將這個方法和類現有的方法進行交換。
②、添加新的方法:
+ (IMP)swizzleSelector:(SEL)origSelector withIMP:(IMP)newIMP { Class class = [self class]; Method origMethod = class_getInstanceMethod(class, origSelector); IMP origIMP = method_getImplementation(origMethod); if(!class_addMethod(self, origSelector, newIMP, method_getTypeEncoding(origMethod))) { method_setImplementation(origMethod, newIMP); } return origIMP; }
具體就不在介紹了。你懂的,,,,
三、總結:
1、在運行期間可以通過方法調配新增或者替換選擇子對應方法的實現。
2、使用另一份實現來替換原有的實現,這道程式就叫做方法調配。
3、一定要注意使用,一般來說只有在偵錯工具的時候才去進行方法調配,很少有人在偵錯工具之外去直接改動某個類的功能。
四、結束語:
method swizzling就介紹這麼多吧,希望能夠協助到大家。