上一篇我們講到iOS對象的底層的本質(zhì)是結(jié)構(gòu)體!!!這一篇我們來看看我們通過
clang -rewrite-objc main.m -o mian.cpp
編譯的對象調(diào)用方法底層
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
LGPerson *p = ((LGPerson *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("LGPerson"), sel_registerName("new"));
((void (*)(id, SEL))(void *)objc_msgSend)((id)p, sel_registerName("run"));
}
return 0;
}
可以看出在我們進(jìn)行LGPerson
初始化的時(shí)候,我們都知道會(huì)調(diào)用alloc
,init
.我這里為了簡單只調(diào)用'new'.但是底層不是像我們利用[]
調(diào)用的,而是調(diào)用了一個(gè)函數(shù)objc_msgSend
這就是我們消息發(fā)送的方法,因?yàn)榭紤]的參數(shù)我們進(jìn)行了前面的強(qiáng)轉(zhuǎn).如果有一定C功底就知道objc_msgSend
就是發(fā)送消息,我們在斷點(diǎn)調(diào)試ViewDidLoad
的時(shí)候,發(fā)現(xiàn)能打印self
,_cmd
這就是我們的消息底層默認(rèn)的兩個(gè)參數(shù)id,SEL
- 一個(gè)是消息接受者
- 一個(gè)是消息編號
我們還可以在objc_msgSend
末尾繼續(xù)加參數(shù),但是考慮到編譯參數(shù)問題,我們需要關(guān)閉嚴(yán)格核查
我通過SEL
能找到函數(shù)實(shí)現(xiàn),底層是依賴一個(gè)IMP的函數(shù)指針
就會(huì)找我們具體的函數(shù)實(shí)現(xiàn)
我們模擬是不是也可不斷發(fā)送消息,模擬四種消息發(fā)送
LGStudent *s = [LGStudent new];
[s run];
// 方法調(diào)用底層編譯
// 方法的本質(zhì): 消息 : 消息接受者 消息編號 ....參數(shù) (消息體)
objc_msgSend(s, sel_registerName("run"));
// 類方法編譯底層
[LGStudent walk];
objc_msgSend(objc_getClass("LGStudent"), sel_registerName("walk"));
// 向父類發(fā)消息(對象方法)
struct objc_super mySuper;
mySuper.receiver = s;
mySuper.super_class = class_getSuperclass([s class]);
objc_msgSendSuper(&mySuper, @selector(run));
//向父類發(fā)消息(類方法)
struct objc_super myClassSuper;
myClassSuper.receiver = [s class];
myClassSuper.super_class = class_getSuperclass(object_getClass([s class]));
objc_msgSendSuper(&myClassSuper, sel_registerName("walk"));