iOS Objective-C的objc runtime isa指針相關

Objective-C是一個面向?qū)ο笳Z言,每一個對象都是一個類的實例。那類和方法調(diào)用的本質(zhì)是什么呢?runtime究竟又是什么呢?這篇文章主要是記錄了解到的相關知識。這部分知識應該是OC中最基礎的部分了,對于深入理解某些知識還是很重要的。

runtime

runtime的概念在官方文檔中有介紹。整理如下,runtime其實是一個runtime庫,能夠提供OC語言的動態(tài)屬性。這個庫是開源的,我們可以在GitHub下載它的源碼看看。
源碼中objc.h中有很多基本類型的定義,比如對象和方法:

// 對象
typedef struct objc_object {
    Class isa;
} *id;

// 方法
typedef struct objc_selector    *SEL;    
typedef id          (*IMP)(id, SEL, ...);

開頭的第二個問題解決了,接下來研究第一個問題。這個問題在源碼中也可以找到答案。

對象

源碼中的Object.h中定義如下:

@interface Object
{
    Class isa;  /* A pointer to the instance's class structure */
}

isa是一個指向?qū)嵗念惤Y構體的指針,那Class到底是什么類型呢?
源碼中的objc_class.h中定義如下:

struct objc_class {         
    struct objc_class *isa; 
    struct objc_class *super_class; 
    const char *name;       
    long version;
    long info;
    long instance_size;
    struct objc_ivar_list *ivars;

#if defined(Release3CompatibilityBuild)
    struct objc_method_list *methods; //Objective-C 2.0
#else
    struct objc_method_list **methodLists; //Objective-C 1.0
#endif

    struct objc_cache *cache;
    struct objc_protocol_list *protocols;
};

接下來搞清楚幾個重要屬性都是什么,
isa:是一個Class類型的指針。 每個Object都有isa指針,指向?qū)ο蟮念?,而Class里也有個isa的指針, 指向meteClass(元類)。元類保存了類方法的列表。當類方法被調(diào)用時,先會從本身查找類方法的實現(xiàn),如果沒有,元類會向他父類查找該方法。同時注意的是:元類(meteClass)也是類,它也是對象。元類也有isa指針,它的isa指針最終指向的是一個根元類(root meteClass).根元類的isa指針指向本身,這樣形成了一個封閉的內(nèi)循環(huán)。

class示意圖.jpg

super_class:指向父類,沒有賊為NULL。
name:類的名稱
ivars:成員變量的數(shù)組
methods:方法的定義列表,對象的方法定義都保存在類的可變區(qū)域中。methodLists是一個指針的指針,通過修改該指針指向的指針的值,就可以實現(xiàn)動態(tài)地為某一個類增加成員方法。這也是Category實現(xiàn)的原理。同時也說明了為什么Category只可為對象增加成員方法,卻不能增加成員變量

方法調(diào)用

Objective-c是一門動態(tài)語言,調(diào)用方法的時候,在運行時,動態(tài)的查找方法,然后調(diào)用相應的函數(shù)地址。

SEL

SEL又叫選擇器,是表示一個方法的selector的指針。Objective-C 在編譯時,會根據(jù)方法的名字生成一個用來區(qū)分這個方法的唯一的一個ID,本質(zhì)上就是一個字符串,即Int類型的地址,這個字符串就是SEL。只要方法名稱相同,那么它們的ID就是相同的。
objc.h中的IMP實際上就是一個函數(shù)指針,指向方法實現(xiàn)的首地址。

在Objective-C中,消息直到運行時才綁定到方法實現(xiàn)上。編譯器會將消息表達式[receiver message]轉化為一個消息函數(shù)的調(diào)用,即objc_msgSend,將消息接收者和方法名作為其基礎參數(shù),如以下所示:

objc_msgSend(receiver, selector)
消息發(fā)送.gif

當消息發(fā)送給一個對象時,objc_msgSend通過對象的isa指針獲取到類的結構體,然后在methods里面查找方法的selector。如果沒有找到selector,則找到其父類,并在父類的分發(fā)表里面查找。依此,會一直沿著類的繼承體系到達NSObject類。一旦定位到selector,函數(shù)就獲取到了實現(xiàn)的入口點,并傳入相應的參數(shù)來執(zhí)行方法的具體實現(xiàn)。如果最后沒有定位到selector,則會走消息轉發(fā)流程。
為了加速消息的處理,運行時系統(tǒng)緩存使用過的selector及對應的方法的地址。

參考文章:
Objective-C對象模型及應用
OC Runtime第一篇---類與對象
Objective-C Runtime 運行時之三:方法與消息

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容