一、消息機(jī)制
頭文件 :<objc/message.h>
設(shè)置:【build Setting】 搜 @“msg” -> Enable strict checking of objc_msgSend calls 設(shè)置 NO

例 : 創(chuàng)建一個(gè)類,調(diào)用方法
OC: Person * p = [[Person alloc] init];
調(diào)用方法一: [p miao];
調(diào)用方法二: [p performSelector:@selector(miao)];
msg: Person * p = [[Person alloc] init];
objc_msgSend(p,@selector(miao));
so: Person * p = [[Person alloc] init] 可以寫成
Person * p = objc_msgSend(Person.class, @selector(alloc));
p = objc_msgSend(p, @selector(init));
完全C語(yǔ)言寫法 :
Person * p = objc_msgSend(objc_getClass("Person"), sel_registerName("alloc"));
p = objc_msgSend(p, @selector(init));
其中 Person.class -> objc_getClass("Person")
@selector(alloc) -> sel_registerName("alloc")
補(bǔ)充: 編譯器會(huì)根據(jù)情況在 objc_msgSend,objc_msgSend_stret,objc_msgSendSuper,objc_msgSendSuper_stret 或 objc_msgSend_fpret 五個(gè)方法中選擇一個(gè)來調(diào)用。如果消息是傳遞給超類,那么會(huì)調(diào)用 objc_msgSendSuper 方法,如果消息返回值是數(shù)據(jù)結(jié)構(gòu),就會(huì)調(diào)用 objc_msgSendSuper_stret 方法,如果返回值是浮點(diǎn)數(shù),則調(diào)用 objc_msgSend_fpret 方法。

當(dāng)調(diào)用 [super class] 時(shí),會(huì)轉(zhuǎn)換成 objc_msgSendSuper 函數(shù):
第一步先構(gòu)造 objc_super 結(jié)構(gòu)體,結(jié)構(gòu)體第一個(gè)成員就是 self。第二個(gè)成員是 (id)class_getSuperclass(objc_getClass(“Son”)).
第二步是去 Father 這個(gè)類里去找 - (Class)class,沒有,然后去 NSObject 類去找,找到了。最后內(nèi)部是使用 objc_msgSend(objc_super->receiver, @selector(class)) 去調(diào)用,此時(shí)已經(jīng)和 [self class] 調(diào)用相同了,所以兩個(gè)輸出結(jié)果都是 Son。
二、runtime 運(yùn)用
頭文件: <objc/runtime.h> 注: <objc/message.h> 包含 <objc/runtime.h>,只用 <objc/message.h> 即可
1、獲取某個(gè)類屬性列表
//屬性個(gè)數(shù) 其中.m 中的屬性 也可以拿到
unsigned int count = 0;
// copy new creat 代表毀在 堆區(qū) (Malloc) 開辟空間
// Ivar 成員屬性
Ivar * list = class_copyIvarList(Person.class, &count);
for (int i = 0; i < count ; i++) {
Ivar ivar = list[i];
//通過 Ivar 拿到屬性名稱
const char * name = ivar_getName(ivar);
NSString * key = [NSString stringWithUTF8String:name];
}
//防止內(nèi)存溢出
free(list);
2、給一個(gè)類動(dòng)態(tài)添加新方法
方法: class_addMethod(<#Class _Nullable __unsafe_unretained cls#>, <#SEL _Nonnull name#>, <#IMP _Nonnull imp#>, <#const char * _Nullable types#>)
參數(shù)說明:
Class: 你要添加新方法的那個(gè)類
SEL name : 要添加的方法
IMP : 指向?qū)崿F(xiàn)方法的指針 就是要添加的方法的實(shí)現(xiàn)部分
types: 要添加的方法的返回值和參數(shù) 集體參照官方文檔
在OC中找不到對(duì)相應(yīng)的實(shí)現(xiàn)方法時(shí) 有補(bǔ)救機(jī)制 即 會(huì)先調(diào)用動(dòng)態(tài)決議方法 該方法解決不了問題 再調(diào)用重定向方法 都解決不了問題是 crash
動(dòng)態(tài)決議方法:

重定向方法:


補(bǔ)充:為什么 能在 方法中調(diào)到 self ?只因?yàn)樗顷P(guān)鍵字?
說明:
OC: void mou(id self , SEL _cmd) ,其中 self,_cmd.默認(rèn)隱藏
C: objc_msgSend(object_getClass("Person"), sel_registerName("mou"))
其中:self 對(duì)應(yīng) Person _cmd 對(duì)應(yīng) sel_registerName("mou")
3.把一個(gè)對(duì)象與另外一個(gè)對(duì)象進(jìn)行關(guān)聯(lián)
objc_setAssociatedObject來把一個(gè)對(duì)象與另外一個(gè)對(duì)象進(jìn)行關(guān)聯(lián)。該函數(shù)需要四個(gè)參數(shù):源對(duì)象,關(guān)鍵字,關(guān)聯(lián)的對(duì)象和一個(gè)關(guān)聯(lián)策略

關(guān)鍵字是一個(gè)void類型的指針。每一個(gè)關(guān)聯(lián)的關(guān)鍵字必須是唯一的。通常都是會(huì)采用靜態(tài)變量來作為關(guān)鍵字。
關(guān)聯(lián)策略表明了相關(guān)的對(duì)象是通過賦值,保留引用還是復(fù)制的方式進(jìn)行關(guān)聯(lián)的;還有這種關(guān)聯(lián)是原子的還是非原子的。這里的關(guān)聯(lián)策略和聲明屬性時(shí)的很類似。這種關(guān)聯(lián)策略是通過使用預(yù)先定義好的常量來表示的。


斷開連接:
斷開關(guān)聯(lián)是使用objc_setAssociatedObject函數(shù),傳入nil值即可。
使用函數(shù)objc_removeAssociatedObjects可以斷開所有關(guān)聯(lián)