Method Swizzling利用了Objective-C的runtime特性邀层,使得我們能動(dòng)態(tài)替換方法的實(shí)現(xiàn)返敬,實(shí)現(xiàn)hook。
runtime
從敲下NSlog(@"hello world!")
開始寥院,就不斷看到runtime這個(gè)詞劲赠。對(duì)于之前沒(méi)接觸過(guò)動(dòng)態(tài)語(yǔ)言的學(xué)習(xí)者來(lái)說(shuō),runtime聽(tīng)起來(lái)陌生又晦澀秸谢。
Objective-C不同于C語(yǔ)言凛澎,它是一門動(dòng)態(tài)語(yǔ)言,這就意味著它將C語(yǔ)言等靜態(tài)語(yǔ)言在編譯和鏈接時(shí)所做的一些工作留到了運(yùn)行時(shí)再處理钮追。比如预厌,在C語(yǔ)言中,編譯時(shí)就可以確定真正調(diào)用哪些函數(shù)元媚;而Objective-C并不能在編譯時(shí)確定轧叽,只有在運(yùn)行時(shí)才會(huì)由名稱找到對(duì)應(yīng)方法。
因?yàn)檫@種特性刊棕,Objective-C需要一種機(jī)制在運(yùn)行時(shí)來(lái)處理編譯后的代碼炭晒,這種機(jī)制就是runtime。Runtime從實(shí)質(zhì)來(lái)講甥角,就是一套用C語(yǔ)言和匯編寫成的底層API恬叹,用于處理編譯后的代碼晚岭。
method
method_name 表示的是方法的名稱赠法,用于唯一標(biāo)識(shí)某個(gè)方法对雪;
method_types 表示的是方法的返回值和參數(shù)類型;
method_imp 是一個(gè)函數(shù)指針当犯,指向方法的實(shí)現(xiàn)垢村。
方法的名稱 name 和方法的實(shí)現(xiàn) imp 是一一對(duì)應(yīng)的。而且可以發(fā)現(xiàn)方法的名稱和參數(shù)類型是分離的嚎卫。
在我們調(diào)用一個(gè)方法時(shí)
[someObject messageName:paremeter]
在runtime底層會(huì)轉(zhuǎn)換成
Objc_msgSend(someObject, @selector(messageName), paremeter)
調(diào)用方法其實(shí)是向一個(gè)對(duì)象發(fā)送消息嘉栓,而查找方法實(shí)現(xiàn)的唯一依據(jù)是selector后接的方法名稱。所以拓诸,利用這一特性侵佃,我們就可以實(shí)現(xiàn)在運(yùn)行時(shí)更改selector對(duì)應(yīng)的方法實(shí)現(xiàn),也就實(shí)現(xiàn)了HOOK奠支。
method swizzling
原理
以上兩圖來(lái)自:念茜
每個(gè)類都維護(hù)著一個(gè)方法列表馋辈,里面存放著selector的名字與方法實(shí)現(xiàn)間的映射關(guān)系。Method Swizzling就是改換了這種對(duì)應(yīng)關(guān)系胚宦。
可以調(diào)用三種方法來(lái)實(shí)現(xiàn)method swizzling:
method_exchangeImplementations
交換2個(gè)方法中的IMP(IMPlication)首有;
class_replaceMethod
修改類燕垃;
利用 method_setImplementation
直接設(shè)置某個(gè)方法的IMP枢劝。
這些方法的聲明都寫在runtime.h
中井联。
1.method_exchangeImplementations
method_exchangeImplementations
通過(guò)交換兩個(gè)方法的IMP實(shí)現(xiàn)hook的,通過(guò)
method_exchangeImplementations(A_Method, B_Method);
可以實(shí)現(xiàn)如下圖的交換您旁。
2.method_setImplementation
method_setImplementation
直接設(shè)置更改某個(gè)方法的IMP烙常。
如下圖,假設(shè)有方法A鹤盒,我們想要把它的實(shí)現(xiàn)替換為方法B的實(shí)現(xiàn)蚕脏,但又不想改變方法B的實(shí)現(xiàn),就可以使用method_setImplementation
侦锯,直接把A的IMP設(shè)置為B的IMP驼鞭。
3.class_replaceMethod
class_replaceMethod
其實(shí)相當(dāng)于class_addMethod
和method_setImplementation
的一個(gè)結(jié)合。
當(dāng)調(diào)用
class_replaceMethod(cls, name, imp, types)
時(shí)尺碰,將把屬于cls
類的name
方法實(shí)現(xiàn)指向imp
挣棕。
如果cls
類原本沒(méi)有name
方法,就相當(dāng)于調(diào)用class_addMethod
給cls
類增添了一個(gè)方法及其實(shí)現(xiàn)亲桥,這個(gè)方法的返回類型由types
給定洛心。
如果cls
類原本就有name
方法,就相當(dāng)于調(diào)用method_setImplementation
更改了name
方法的實(shí)現(xiàn)為imp
题篷,返回類型由替換的實(shí)現(xiàn)imp
決定词身,給定types
將被忽略。
參考
Objective-C的hook方案(一): Method Swizzling
Hook 原理之 Method Swizzling