[OC Runtime編程指南_翻譯]一算凿、介紹
[OC Runtime編程指南_翻譯]二凳谦、運(yùn)行時(shí)版本和平臺(tái)
[OC Runtime編程指南_翻譯]三忆畅、與運(yùn)行時(shí)交互
[OC Runtime編程指南_翻譯]四、消息傳遞
[OC Runtime編程指南_翻譯]五尸执、動(dòng)態(tài)方法解析
[OC Runtime編程指南_翻譯]六家凯、消息轉(zhuǎn)發(fā)
[OC Runtime編程指南_翻譯]七、類型編碼
[OC Runtime編程指南_翻譯]八剔交、聲明屬性注:pdf翻譯文檔百度云下載鏈接肆饶,密碼:zcs2
本章介紹如何將消息表達(dá)式轉(zhuǎn)換為objc_msgSend函數(shù)調(diào)用,以及如何按名稱引用方法岖常。然后解釋如何利用objc_msgSend
驯镊,以及如果需要,如何繞過(guò)動(dòng)態(tài)綁定竭鞍。
objc_msgSend 函數(shù)(重要0寤蟆!Y丝臁)
在Objective-C中冯乘,消息直到運(yùn)行時(shí)才綁定到方法實(shí)現(xiàn)
。編譯器轉(zhuǎn)換消息表達(dá)式晒夹,
[receiver message]
調(diào)用消息傳遞函數(shù) objc_msgSend
裆馒。此函數(shù)將接收方和消息中提到的方法的名稱(即方法選擇器)作為其兩個(gè)主要參數(shù):
objc_msgSend(receiver, selector)
消息中傳遞的任何參數(shù)也將傳遞給objc_msgSend:
objc_msgSend(receiver, selector, arg1, arg2, ...)
消息傳遞函數(shù)為動(dòng)態(tài)綁定
:
- 先
綁定
查找選擇器引用的過(guò)程(方法實(shí)現(xiàn))。由于同一方法可以由不同的類實(shí)現(xiàn)丐怯,因此它找到的精確過(guò)程取決于接受者喷好。 - 它然后
調(diào)用
過(guò)程,將接收對(duì)象(指向其數(shù)據(jù)的指針)以及為方法读跷。 - 最后梗搅,它
傳遞
過(guò)程的返回值作為自己的回報(bào)值。
注意:編譯器生成對(duì)消息傳遞函數(shù)的調(diào)用。永遠(yuǎn)不要在編寫(xiě)的代碼中直接調(diào)用它无切。
消息傳遞的關(guān)鍵在于編譯器為每個(gè)類和對(duì)象構(gòu)建的結(jié)構(gòu)
荡短。每個(gè)類結(jié)構(gòu)都包含以下兩個(gè)基本元素
:
-
指向超類的指針
。 -
一個(gè)類調(diào)度表
哆键。此表中的條目將方法選擇器(selector)與
其標(biāo)識(shí)的方法
的類特定地址相關(guān)聯(lián)
掘托。setOrigin:
方法的選擇器與setOrigin:
(實(shí)現(xiàn)的過(guò)程)的地址相關(guān)聯(lián),display
方法的選擇器與display
的地址關(guān)聯(lián)洼哎,依此類推烫映。
創(chuàng)建新對(duì)象時(shí),將為其分配內(nèi)存噩峦,并初始化其實(shí)例變量
锭沟。對(duì)象變量中的第一個(gè)變量是指向其類結(jié)構(gòu)的指針
。這個(gè)名為isa
的指針讓對(duì)象訪問(wèn)其類识补,并通過(guò)該類訪問(wèn)它繼承的所有類族淮。
注意:雖然isa指針不是嚴(yán)格意義上的語(yǔ)言的一部分,但它是對(duì)象與Objective-C運(yùn)行時(shí)系統(tǒng)一起工作所必需的凭涂。在結(jié)構(gòu)定義的任何字段中祝辣,對(duì)象都需要與struct objc_object(在objc/objc.h中定義)“等效”。但是切油,您很少需要?jiǎng)?chuàng)建自己的根對(duì)象蝙斜,并且從NSObject或NSProxy繼承的對(duì)象自動(dòng)具有isa變量
。
這些類元素和對(duì)象結(jié)構(gòu)如圖3-1所示澎胡。
Figure 3-1 Messaging Framework
當(dāng)消息發(fā)送到對(duì)象
時(shí)孕荠,消息傳遞函數(shù)跟隨對(duì)象的isa
指針指向類結(jié)構(gòu)
,在該類結(jié)構(gòu)中查找調(diào)度表中的方法選擇器
攻谁。如果在那里找不到
選擇器稚伍,objc_msgSend
會(huì)跟隨指向超類的指針
并嘗試在其調(diào)度表中查找選擇器
。連續(xù)的失敗導(dǎo)致objc_msgSend爬升類層次結(jié)構(gòu)戚宦,直到到達(dá)NSObject類
个曙。一旦找到選擇器,函數(shù)就會(huì)調(diào)用表中輸入的方法受楼,并將接收對(duì)象的數(shù)據(jù)結(jié)構(gòu)傳遞給它垦搬。
這就是在運(yùn)行時(shí)選擇方法實(shí)現(xiàn)的方式
,或者用面向?qū)ο缶幊痰男性拋?lái)說(shuō)艳汽,方法是動(dòng)態(tài)綁定到消息的
猴贰。
為了加快消息傳遞過(guò)程
,運(yùn)行時(shí)系統(tǒng)在使用方法時(shí)緩存選擇器和地址
骚灸。每個(gè)類都有一個(gè)單獨(dú)的緩存
糟趾,它可以包含繼承方法的選擇器以及類中定義的方法的選擇器慌植。在搜索調(diào)度表之前甚牲,消息傳遞例程首先檢查接收對(duì)象類的緩存
(理論上义郑,曾經(jīng)使用過(guò)一次的方法可能會(huì)再次使用)。如果方法選擇器在緩存中丈钙,則消息傳遞只比函數(shù)調(diào)用稍慢
非驮。一旦一個(gè)程序運(yùn)行足夠長(zhǎng)的時(shí)間來(lái)“預(yù)熱”它的緩存,它發(fā)送的幾乎所有消息都會(huì)找到一個(gè)緩存方法雏赦。緩存動(dòng)態(tài)增長(zhǎng)以適應(yīng)程序運(yùn)行時(shí)的新消息劫笙。
使用隱藏參數(shù)
當(dāng) objc_msgSend找到實(shí)現(xiàn)方法的過(guò)程時(shí),它調(diào)用該過(guò)程并將消息中的所有參數(shù)傳遞給它星岗。它還向過(guò)程傳遞兩個(gè)隱藏參數(shù)
:
接收對(duì)象
方法的選擇器
這些參數(shù)為每個(gè)方法實(shí)現(xiàn)提供關(guān)于調(diào)用它的消息表達(dá)式的兩部分的顯式信息填大。它們被稱為“隱藏”,因?yàn)樗鼈?code>沒(méi)有在定義方法的源代碼中聲明俏橘。它們?cè)诖a編譯時(shí)被插入到實(shí)現(xiàn)中允华。
雖然這些參數(shù)沒(méi)有顯式聲明,但是源代碼仍然可以引用它們(就像它可以引用接收對(duì)象的實(shí)例變量一樣)寥掐。方法將接收對(duì)象
引用為self
靴寂,并將其自己的選擇器
引用為_cmd
。在下面的示例中召耘,_cmd
表示異常方法的選擇器百炬,self
指向接收到異常消息的對(duì)象。
- strange
{
//_cmd:表示異常的選擇器
//self:指向接收到異常消息的對(duì)象
id target = getTheReceiver();
SEL method = getTheMethod();
if ( target == self || method == _cmd )
return nil;
return [target performSelector:method];
}
在這兩個(gè)論點(diǎn)中污它,self更有用剖踊。實(shí)際上,這是接收對(duì)象的實(shí)例變量可用于方法定義的方式
獲取方法地址
規(guī)避動(dòng)態(tài)綁定的唯一方法是獲取方法的地址轨蛤,然后像函數(shù)一樣直接調(diào)用它
蜜宪。當(dāng)一個(gè)特定的方法將被連續(xù)執(zhí)行很多次,并且您希望避免每次執(zhí)行該方法時(shí)消息傳遞的開(kāi)銷祥山,這種情況可能比較合適圃验。
使用NSObject
類中定義的方法methodForSelector:
,可以請(qǐng)求指向?qū)崿F(xiàn)方法的過(guò)程的指針缝呕,然后使用該指針調(diào)用該過(guò)程
澳窑。methodForSelector:
返回的指針必須謹(jǐn)慎
地轉(zhuǎn)換
為正確的函數(shù)類型
。類型轉(zhuǎn)換中應(yīng)包括返回類型和參數(shù)類型供常。
下面的示例顯示如何調(diào)用實(shí)現(xiàn)setFilled:方法的過(guò)程:
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);
傳遞給過(guò)程的前兩個(gè)參數(shù)是接收對(duì)象(self)
和方法選擇器(_cmd)
摊聋。這些參數(shù)隱藏在方法語(yǔ)法中,但必須在方法作為函數(shù)調(diào)用時(shí)顯式栈暇。
使用methodForSelector:
繞過(guò)動(dòng)態(tài)綁定可以節(jié)省消息傳遞所需的大部分時(shí)間麻裁。但是,只有在特定的消息被重復(fù)多次時(shí),節(jié)省的空間才會(huì)顯著煎源,如上面所示的for循環(huán)中色迂。
注意methodForSelector:
是由Cocoa運(yùn)行時(shí)系統(tǒng)提供的
;它不是Objective-C語(yǔ)言本身的特性
手销。