Hook原理介紹
1.Objective-C消息傳遞(Messaging)
對(duì)于C/C++這類(lèi)靜態(tài)語(yǔ)言贴铜,調(diào)用一個(gè)方法其實(shí)就是跳到內(nèi)存中的某一點(diǎn)并開(kāi)始執(zhí)行一段代碼抑进。沒(méi)有任何動(dòng)態(tài)的特性占贫,因?yàn)檫@在編譯時(shí)就決定好了琅锻。
而在 Objective-C 中帮掉,[object foo] 語(yǔ)法并不會(huì)立即執(zhí)行 foo 這個(gè)方法的代碼咙俩。它是在運(yùn)行時(shí)給 object 發(fā)送一條叫 foo 的消息耿戚。這個(gè)消息湿故,也許會(huì)由 object 來(lái)處理,也許會(huì)被轉(zhuǎn)發(fā)給另一個(gè)對(duì)象膜蛔,或者不予理睬假裝沒(méi)收到這個(gè)消息坛猪。多條不同的消息也可以對(duì)應(yīng)同一個(gè)方法實(shí)現(xiàn)。這些都是在程序運(yùn)行的時(shí)候動(dòng)態(tài)決定的皂股。
事實(shí)上墅茉,在編譯時(shí)你寫(xiě)的 Objective-C 函數(shù)調(diào)用的語(yǔ)法都會(huì)被翻譯成一個(gè) C 的函數(shù)調(diào)用 objc_msgSend() 。比如呜呐,下面兩行代碼就是等價(jià)的:
[people TailName:@"Test" Age:18];
objc_msgSend(people, @selector(TailName:Age:), "Test", 18);
在 Objective-C 中就斤,類(lèi)、對(duì)象和方法都是一個(gè)C的結(jié)構(gòu)體蘑辑,從 objc/objc.h 和 objc/runtime.h 頭文件中洋机,我們可以找到他們的定義:
typedef struct objc_class *Class;
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
typedef struct objc_object *id;
//Class 是一個(gè) objc_class 結(jié)構(gòu)類(lèi)型的指針, id是一個(gè) objc_object 結(jié)構(gòu)類(lèi)型的指針.
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class
const char *name
long version
long info
long instance_size
struct objc_ivar_list *ivars
struct objc_method_list **methodLists
struct objc_cache *cache
struct objc_protocol_list *protocols
#endif
} OBJC2_UNAVAILABLE;
isa
是一個(gè) objective-c Class 類(lèi)型的指針. 實(shí)例對(duì)象有個(gè)isa的屬性,指向Class, 而Class里也有個(gè)isa的屬性, 指向meteClass. 這里就有個(gè)點(diǎn), 在Objective-C中任何的類(lèi)定義都是對(duì)象.super_class
指向該類(lèi)的父類(lèi), 如果該類(lèi)已經(jīng)是最頂層的根類(lèi)(如 NSObject 或 NSProxy),那么 super_class 就為 NULL.

name
類(lèi)的名字version
類(lèi)的版本信息,默認(rèn)為0info
供運(yùn)行期使用的一些位標(biāo)識(shí)。instance_size
該類(lèi)的實(shí)例變量大小ivars
成員變量的鏈表
struct objc_ivar_list {
int ivar_count
/* variable length structure */
struct objc_ivar ivar_list[1]
}
- methodLists
方法定義的鏈表struct objc_method_list { struct objc_method_list *obsolete; int method_count; struct objc_method method_list[1]; }; struct objc_method { SEL method_name; char *method_types; IMP method_imp;
};
- objc_cache
指向最近使用的方法.用于方法調(diào)用的優(yōu)化
struct objc_cache {
unsigned int mask /* total = mask + 1 */;
unsigned int occupied;
Method buckets[1];
};
- protocols
協(xié)議的鏈表
struct objc_protocol_list {
struct objc_protocol_list *next;
long count;
Protocol *list[1];
};
objc_method_list 本質(zhì)是一個(gè)有 objc_method 元素的可變長(zhǎng)度的數(shù)組洋魂。一個(gè) objc_method 結(jié)構(gòu)體中:
- 函數(shù)名绷旗,也就是SEL
- 表示函數(shù)原型的字符串 (見(jiàn) Type Encoding)
- 函數(shù)的實(shí)現(xiàn)IMP
#### 2. Method Swizzling示例
以上面可知方法的名字(SEL)跟方法的實(shí)現(xiàn)(IMP,指向 C 函數(shù)的指針)一一對(duì)應(yīng)忧设。Swizzle 一個(gè)方法其實(shí)就是在程序運(yùn)行時(shí)對(duì) objc_method_list 里做點(diǎn)改動(dòng)刁标,讓這個(gè)方法的名字(SEL)對(duì)應(yīng)到另個(gè)IMP颠通。
Method Swizzling(方法調(diào)配技術(shù))址晕,僅針對(duì)Objective-C方法有效。Method Swizzling 利用 Runtime 特性把一個(gè)方法的實(shí)現(xiàn)與另一個(gè)方法的實(shí)現(xiàn)進(jìn)行替換顿锰。
//涉及到的主要方法
class_addMethod
class_replaceMethod
method_exchangeImplementations