Introduction
The Objective-C language defers as many decisions as it can from compile time and link time to runtime. Whenever possible, it does things dynamically. This means that the language requires not just a compiler, but also a runtime system to execute the compiled code.
OC是一種面向?qū)ο蟮膭?dòng)態(tài)語(yǔ)言,動(dòng)態(tài)語(yǔ)言就是在運(yùn)行時(shí)來(lái)執(zhí)行靜態(tài)語(yǔ)言的編譯鏈接的工作。這就要求除了編譯器之外還要有一種運(yùn)行時(shí)系統(tǒng)來(lái)執(zhí)行編譯等功能。OC中這個(gè)系統(tǒng)就是runtime。
- 編譯時(shí)間指編譯程序?qū)⒃闯绦蚓幾g成目標(biāo)程序所占用的時(shí)間。
- 源程序,是指未經(jīng)編譯的,按照一定的程序設(shè)計(jì)語(yǔ)言規(guī)范書寫的,人類可讀的文本文件。通常由高級(jí)語(yǔ)言編寫。
- 目標(biāo)程序,又稱為“目的程序”,為源程序經(jīng)編譯可直接被計(jì)算機(jī)運(yùn)行的機(jī)器碼集合,在計(jì)算機(jī)文件上以.obj作擴(kuò)展名。目標(biāo)代碼盡管已經(jīng)是機(jī)器指令,但是還不能運(yùn)行,因?yàn)槟繕?biāo)程序還沒(méi)有解決函數(shù)調(diào)用問(wèn)題,需要將各個(gè)目標(biāo)程序與庫(kù)函數(shù)連接,才能形成完整的可執(zhí)行程序。
Messaging
這一章描述了:
- 消息表達(dá)式(message expression)如何轉(zhuǎn)換為objc_msgSend函數(shù)調(diào)用。
- 如何通過(guò)名稱(name)來(lái)引用方法(methods)。
- 說(shuō)明如何充分利用objc_msgSend。
- 如何規(guī)避(circumvent)動(dòng)態(tài)綁定(dynamic binding)。
The objc_msgSend Function
[receiver message]
在OC中,消息(message)在運(yùn)行時(shí)(runtime)才被綁定到方法實(shí)現(xiàn)。編譯器(compiler)把消息轉(zhuǎn)換(convert to)為函數(shù)objc_msgSend的調(diào)用。objc_msgSend將接收方(receiver)和消息中提到的方法的名稱(即selector)作為函數(shù)的兩個(gè)重要的參數(shù):
objc_msgSend(receiver, selector)
消息中所有參數(shù)(arguments)也會(huì)傳遞給objc_msgSend函數(shù):
objc_msgSend(receiver, selector, arg1, arg2, ...)
objc_msgSend為動(dòng)態(tài)綁定執(zhí)行所需的一切。
- 首先,它查找selector引用的實(shí)現(xiàn)方法。(因?yàn)橄嗤姆椒梢员徊煌念悓?shí)現(xiàn),所以定位精確的實(shí)現(xiàn)方法取決于receiver的的類型)
- 然后,調(diào)用實(shí)現(xiàn)方法,把receiver和方法指定的參數(shù)傳遞給它。
- 最后,把實(shí)現(xiàn)方法的返回值作為它的返回值。
note:編譯器生成對(duì)objc_msgSend的調(diào)用,你不要直接在代碼中直接調(diào)用它
消息傳遞的關(guān)鍵依賴于編譯器為每個(gè)類和對(duì)象創(chuàng)建的結(jié)構(gòu)(structures),每個(gè)類結(jié)構(gòu)包含兩個(gè)基本(essential)元素:
- 一個(gè)指向父類的指針(A point to the superclass)
- 一個(gè)類的調(diào)度表(A class dispatch table)。這個(gè)表?yè)碛袑⒎椒ㄟx擇器(method selector)與特定類的方法地址相關(guān)聯(lián)的條目(entries)。例如:setOrigin::的selector與setOrigin::的實(shí)現(xiàn)方法(implementation)地址關(guān)聯(lián)起來(lái)。
當(dāng)創(chuàng)建一個(gè)新對(duì)象時(shí),內(nèi)存會(huì)為它分配空間,并且它的實(shí)例變量會(huì)被初始化。這個(gè)對(duì)象的所有變量中第一個(gè)是isa指針(指向它的類structure),object可以根據(jù)isa訪問(wèn)它的類和父類。

當(dāng)一個(gè)objc_msgSend發(fā)送給一個(gè)對(duì)象時(shí),沿著isa查找類結(jié)構(gòu)中調(diào)度表(dispatch table)中的selector對(duì)應(yīng)的實(shí)現(xiàn)方法的地址(address)。如果沒(méi)有找到對(duì)應(yīng)的selector,則繼續(xù)沿著isa查找父類的dispatch table的selector。連續(xù)的失?。╯uccessive failures)導(dǎo)致objc_msgSend遍歷層級(jí),直到遍歷到NSObject。
為了加快消息傳遞速度,runtime系統(tǒng)會(huì)緩沖(cache)已經(jīng)使用過(guò)的selectors和addresses of methods。每一個(gè)類都單獨(dú)(seperate)創(chuàng)建cache緩沖繼承(inherited)的和定義的方法。
Using Hidden Arguments
當(dāng)objc_msgSend找到方法實(shí)現(xiàn)的地址,調(diào)用方法,并把message中的arguments傳遞給它。同時(shí),也包含兩個(gè)隱藏的(hidden)arguments。
- 接受消息的對(duì)象(The receiving object)。
- 方法的選擇器(The selector for the method)。
這兩個(gè)參數(shù)為方法實(shí)現(xiàn)提供了明確的信息:消息表達(dá)式的兩半(即[receiver message])。方法將receiving object引用為self,將selector引用為_(kāi)cmd。
Getting a Method Address
void (*setter)(id, SEL, BOOL);
int i;
setter = (void(*)(id, SEL, BOOL))[target methodForSelector:@selector(setFilled:)];
for (i = 0, i < 1000, i++) {
setter(targetList(i), @selector(setFilled:), YES);
}
阻止動(dòng)態(tài)綁定的唯一方式:獲取方法的地址(addresss),直接調(diào)用它(如果它是一個(gè)函數(shù))。這種情況只適合在連續(xù)多次調(diào)用某個(gè)方法的時(shí)候,可以減少動(dòng)態(tài)綁定的消耗。
NSObject的methodForSelector:返回一個(gè)方法(method)的指針(pointer),用這個(gè)pointer去實(shí)現(xiàn)一個(gè)方。methodForSelector:返回的指針必須小心的轉(zhuǎn)換為正確的函數(shù)類型。返回和參數(shù)類型都應(yīng)該包含在轉(zhuǎn)換中。例如:
void (*setter)(id, SEL, BOOL);
int i;
setter = (void(*)(id, SEL, BOOL))[target methodForSelector:@selector(setFilled:)];
接受對(duì)象(receiving object)和方法選擇器(method selecotr),這兩個(gè)參數(shù)(arguments)在方法語(yǔ)法中(method syntax)中是被隱藏的,但是方法作為函數(shù)(function)調(diào)用時(shí),必須是顯示的(explicit)。例如:
setter(targetList(i), @selector(setFilled:), YES);
使用methodForSelector:阻止動(dòng)態(tài)綁定在消息傳遞中節(jié)省了大部分時(shí)間,但是這大部分時(shí)間只有在以下情況才有意義:某個(gè)確定的方法連續(xù)的調(diào)用。如在for loop。
note:methodForSelector:由Cocoa runtime system提供,不是Objective-C語(yǔ)言的特定。