Cocoa 之消息

了解三個(gè)概念Class, SEL, IMP,它們?cè)趏bjc/objc.h 中定義:

typedef struct objc_class *Class;

typedef struct objc_object {

    Class isa;

} *id;

typedef struct objc_selector   *SEL;   

typedef id (*IMP)(id, SEL, ...);
struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class super_class                                        OBJC2_UNAVAILABLE;
    const char *name                                         OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */

Class 是指向類(lèi)結(jié)構(gòu)體的指針,該類(lèi)結(jié)構(gòu)體含有一個(gè)指向其父類(lèi)類(lèi)結(jié)構(gòu)的指針,該類(lèi)方法的鏈表,該類(lèi)方法的緩存以及其他必要信息。

NSObject 的class 方法就返回這樣一個(gè)指向其類(lèi)結(jié)構(gòu)的指針。每一個(gè)類(lèi)實(shí)例對(duì)象的第一個(gè)實(shí)例變量是一個(gè)指向該對(duì)象的類(lèi)結(jié)構(gòu)的指針,叫做isa。通過(guò)該指針,對(duì)象可以訪問(wèn)它對(duì)應(yīng)的類(lèi)以及相應(yīng)的父類(lèi)。如圖一所示:

class superclass.gif

如圖一所示,圓形所代表的實(shí)例對(duì)象的第一個(gè)實(shí)例變量為 isa,它指向該類(lèi)的類(lèi)結(jié)構(gòu) The object’s class。而該類(lèi)結(jié)構(gòu)有一個(gè)指向其父類(lèi)類(lèi)結(jié)構(gòu)的指針superclass, 以及自身消息名稱(selector)/實(shí)現(xiàn)地址(address)的方法鏈表。

方法的含義:
注意這里所說(shuō)的方法鏈表里面存儲(chǔ)的是Method 類(lèi)型的。圖一中selector 就是指 Method的 SEL, address就是指Method的 IMP。 Method 在頭文件 objc_class.h中定義如下:

typedef struct objc_method *Method;

typedef struct objc_ method {

    SEL method_name;

    char *method_types;

    IMP method_imp;

};

方法 Method,其包含
一個(gè) SEL – 表示該方法的名稱
一個(gè)types – 表示該方法參數(shù)的類(lèi)型
一個(gè) IMP - 指向該方法的具體實(shí)現(xiàn)的函數(shù)指針

不同的類(lèi)可以擁有相同的 selector,這個(gè)沒(méi)有問(wèn)題,因?yàn)椴煌?lèi)的實(shí)例對(duì)象performSelector相同的 selector 時(shí),會(huì)在各自的消息選標(biāo)(selector)/實(shí)現(xiàn)地址(address) 方法鏈表中根據(jù) selector 去查找具體的方法實(shí)現(xiàn)IMP, 然后用這個(gè)方法實(shí)現(xiàn)去執(zhí)行具體的實(shí)現(xiàn)代碼。這是一個(gè)動(dòng)態(tài)綁定的過(guò)程,在編譯的時(shí)候,我們不知道最終會(huì)執(zhí)行哪一些代碼,只有在執(zhí)行的時(shí)候,通過(guò)selector去查詢,我們才能確定具體的執(zhí)行代碼。

IMP 的含義:
在前面我們也看到 IMP 的定義為:
typedef id (*IMP)(id, SEL, ...);

至此,我們就很清楚地知道 IMP 的含義:IMP 是一個(gè)函數(shù)指針,這個(gè)被指向的函數(shù)包含一個(gè)接收消息的對(duì)象id(self 指針), 調(diào)用方法的選標(biāo) SEL (方法名),以及不定個(gè)數(shù)的方法參數(shù),并返回一個(gè)id。也就是說(shuō) IMP 是消息最終調(diào)用的執(zhí)行代碼,是方法真正的實(shí)現(xiàn)代碼 。我們可以像在C語(yǔ)言里面一樣使用這個(gè)函數(shù)指針。

消息傳遞(Messaging)

在 Objective-C 中,[object foo]語(yǔ)法并不會(huì)立即執(zhí)行 foo 這個(gè)方法的代碼。它是在運(yùn)行時(shí)給 object 發(fā)送一條叫 foo 的消息。這個(gè)消息,也許會(huì)由 object 來(lái)處理,也許會(huì)被轉(zhuǎn)發(fā)給另一個(gè)對(duì)象,或者不予理睬假裝沒(méi)收到這個(gè)消息。多條不同的消息也可以對(duì)應(yīng)同一個(gè)方法實(shí)現(xiàn)。這些都是在程序運(yùn)行的時(shí)候決定的。

從這些定義中可以看出發(fā)送一條消息也就 objc_msgSend做了什么事。舉 objc_msgSend(obj, foo)
這個(gè)例子來(lái)說(shuō):
1.首先,通過(guò) obj 的 isa 指針找到它的 class ;
2.在 class 的 method list 找 foo ;
3.如果 class 中沒(méi)到 foo,繼續(xù)往它的 superclass 中找 ;
4.一旦找到 foo 這個(gè)函數(shù),就去執(zhí)行它的實(shí)現(xiàn)IMP .

但這種實(shí)現(xiàn)有個(gè)問(wèn)題,效率低。但一個(gè) class 往往只有 20% 的函數(shù)會(huì)被經(jīng)常調(diào)用,可能占總調(diào)用次數(shù)的 80% 。每個(gè)消息都需要遍歷一次 objc_method_list并不合理。如果把經(jīng)常被調(diào)用的函數(shù)緩存下來(lái),那可以大大提高函數(shù)查詢的效率。這也就是 objc_class中另一個(gè)重要成員 objc_cache做的事情 - 再找到 foo 之后,把 foo 的 method_name作為 key ,method_imp作為 value 給存起來(lái)。當(dāng)再次收到 foo 消息的時(shí)候,可以直接在 cache 里找到,避免去遍歷 objc_method_list.

首先,編譯器將代碼[obj makeText];轉(zhuǎn)化為objc_msgSend(obj, @selector (makeText));,在objc_msgSend函數(shù)中。首先通過(guò)obj的isa指針找到obj對(duì)應(yīng)的class。在Class中先去cache中 通過(guò)SEL查找對(duì)應(yīng)函數(shù)method(猜測(cè)cache中method列表是以SEL為key通過(guò)hash表來(lái)存儲(chǔ)的,這樣能提高函數(shù)查找速度),若 cache中未找到。再去methodList中查找,若methodlist中未找到,則取superClass中查找。若能找到,則將method加 入到cache中,以方便下次查找,并通過(guò)method中的函數(shù)指針跳轉(zhuǎn)到對(duì)應(yīng)的函數(shù)中去執(zhí)行。

參考:
http://blog.csdn.net/kesalin/article/details/6689226

http://southpeak.github.io/blog/2014/10/25/objective-c-runtime-yun-xing-shi-zhi-lei-yu-dui-xiang/

http://tech.glowing.com/cn/objective-c-runtime/

http://blog.csdn.net/a19860903/article/details/44853841

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,768評(píng)論 0 9
  • 在入門(mén)級(jí)別的ObjC 教程中,我們常對(duì)從C++或Java 或其他面向?qū)ο笳Z(yǔ)言轉(zhuǎn)過(guò)來(lái)的程序員說(shuō),ObjC 中的方法調(diào)...
    Mr_Baymax閱讀 262評(píng)論 4 3
  • 我們常常會(huì)聽(tīng)說(shuō) Objective-C 是一門(mén)動(dòng)態(tài)語(yǔ)言,那么這個(gè)「動(dòng)態(tài)」表現(xiàn)在哪呢?我想最主要的表現(xiàn)就是 Obje...
    Ethan_Struggle閱讀 2,231評(píng)論 0 7
  • 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,620評(píng)論 33 466
  • 如果可以可不可以放縱一下自己 如果可以可不可以消極地隱居山林 如果可以可不可以不再拼搏 如果可以可不可以只做自己喜...
    紫玉云瀟閱讀 248評(píng)論 0 1