[OC Runtime編程指南_翻譯]四、消息傳遞

[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

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ǔ)言本身的特性手销。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末歇僧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子锋拖,更是在濱河造成了極大的恐慌诈悍,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件兽埃,死亡現(xiàn)場(chǎng)離奇詭異侥钳,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)柄错,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)慕趴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人鄙陡,你說(shuō)我怎么就攤上這事冕房。” “怎么了趁矾?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵耙册,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我毫捣,道長(zhǎng)详拙,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任蔓同,我火速辦了婚禮饶辙,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘斑粱。我一直安慰自己弃揽,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布则北。 她就那樣靜靜地躺著矿微,像睡著了一般。 火紅的嫁衣襯著肌膚如雪尚揣。 梳的紋絲不亂的頭發(fā)上涌矢,一...
    開(kāi)封第一講書(shū)人閱讀 51,562評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音快骗,去河邊找鬼娜庇。 笑死塔次,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的名秀。 我是一名探鬼主播俺叭,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼泰偿!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起蜈垮,我...
    開(kāi)封第一講書(shū)人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤耗跛,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后攒发,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體调塌,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年惠猿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了羔砾。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡偶妖,死狀恐怖姜凄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情趾访,我是刑警寧澤态秧,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站扼鞋,受9級(jí)特大地震影響申鱼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜云头,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一捐友、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧溃槐,春花似錦匣砖、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至影涉,卻和暖如春变隔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蟹倾。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工匣缘, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留猖闪,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓肌厨,卻偏偏與公主長(zhǎng)得像培慌,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子柑爸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355