在對象上調(diào)用方法,術(shù)語叫做“傳遞消息”,消息有“名稱”和“選擇器(方法)”,可以接收參數(shù),還可能有返回值。OC是C的超集,C語言使用靜態(tài)綁定,在編譯期間就能決定運(yùn)行時(shí)做調(diào)用的函數(shù)。
#include <stdio.h>void PRintHello() { printf("hello, world!/n");}void printGoodbye() { printf("Goodbye, world!/n");}void doTheThing(int type) { if (type == 0) { printHello(); } else { printGoodbye(); }}編譯器在編譯代碼的時(shí)候就知道有printHello和printGoodbye兩個(gè)函數(shù)了,會直接生成調(diào)用這些函數(shù)的指令,函數(shù)地址實(shí)際上是硬編碼在指令之中。#include <stdio.h>void printHello() { printf("hello, world!/n");}void printGoodbye() { printf("Goodbye, world!/n");}void doTheThing(int type) { void (*fnc)(); if (type == 0) { fnc = printHello; } else { fnc = printGoodbye; } fnc();}如果代碼變成這樣,就得使用“動(dòng)態(tài)綁定”,因?yàn)樗{(diào)用的函數(shù)直到運(yùn)行期才能確定,第一個(gè)例子中,if 和 else 中都有函數(shù)調(diào)用指令,第二個(gè)例子中只有一個(gè)函數(shù)調(diào)用指令,待調(diào)用的函數(shù)地址無法硬編碼在指令中,要在運(yùn)行期讀取出來。給對象發(fā)送消息可以這么寫:
id returnValue = [someObject messageName:parameter];someObject叫做“接受者”,messageName叫做“選擇器”,選擇器與參數(shù)合起來叫做“消息”。編譯器將上述語句轉(zhuǎn)換為C語言函數(shù)調(diào)用 “objc_msgSend”void objc_msgSend(id self, SEL cmd, ...)這是個(gè)“參數(shù)個(gè)數(shù)可變的函數(shù)”,能接受兩個(gè)或兩個(gè)以上的參數(shù)。第一個(gè)參數(shù)代表接受者,第二個(gè)參數(shù)代表選擇器,后續(xù)參數(shù)是消息中的參數(shù)編譯器會把剛才的例子轉(zhuǎn)換為如下函數(shù)。id returnValue = objc_msgSend(someObject, @selector(messageName:), parameter);objc_msgSend 會在接受者所屬的類中搜尋其“方法列表”,如果找到與“選擇器”名稱相符的代碼就實(shí)現(xiàn),沒找到就延繼承體系向上查找,最終找不到,就實(shí)現(xiàn)“消息轉(zhuǎn)發(fā)”。備注:每個(gè)類都有一塊緩存“快速映射表”,如果稍后還向該類發(fā)送相同的消息,執(zhí)行就快。
運(yùn)行環(huán)境中一些“邊界情況”,需要其他函數(shù)處理 1.objc_msgSend_stret:如果待發(fā)送的消息要返回結(jié)構(gòu)體,交給這個(gè)函數(shù)。 2.objc_msgSend_fpre:如果消息返回的是浮點(diǎn)數(shù),交給這個(gè)函數(shù)。 3.objc_msgSendSuper:給超類發(fā)消息,用這個(gè)函數(shù)。也有與objc_msgSend_fpre和objc_msgSend_fpre等效的處理超類消息的方法。
OC對象的每個(gè)方法都可以看做簡單的C函數(shù),原型如下:
<return_type> Class_selector(id self, SEL _cmd, ...)每個(gè)類里都會有一張表格,其中的指針都會指向這種函數(shù),選擇器的名稱則是查表時(shí)用的“鍵”,objc_msgSend用這張表來尋找應(yīng)該執(zhí)行的方法并跳轉(zhuǎn)實(shí)現(xiàn)。“尾調(diào)用優(yōu)化”:如果函數(shù)的最后一項(xiàng)操作是調(diào)用另外一個(gè)函數(shù),編譯器會生成調(diào)轉(zhuǎn)至另一個(gè)函數(shù)所用的指令碼。不會向調(diào)用堆棧中推入新的“棧幀”。注意:只有當(dāng)函數(shù)的最后一項(xiàng)操作僅僅是調(diào)用其他函數(shù)而不會將其返回值另做他用時(shí)
新聞熱點(diǎn)
疑難解答