iOS runtime的詳解

Runtime 又叫運行時,是一套底層的 C 語言 API,其為 iOS 內(nèi)部的核心之一,我們平時編寫的 OC 代碼,底層都是基于它來實現(xiàn)的。比如:

[receiver message];

底層運行時會被編譯器轉(zhuǎn)化為:

objc_msgSend(receiver, selector)

如果其還有參數(shù)比如:

[receiver message:(id)arg...];

底層運行時會被編譯器轉(zhuǎn)化為:

objc_msgSend(receiver, selector, arg1, arg2, ...)

Runtime 的作用
Objc 在三種層面上與 Runtime 系統(tǒng)進行交互:

1、 通過 Objective-C 源代碼(編譯器會將 OC 代碼轉(zhuǎn)換成運行時代碼,在運行時確定數(shù)據(jù)結(jié)構(gòu)和函數(shù)。)
2、 通過 Foundation 框架的 NSObject 類定義的方法

Cocoa 程序中絕大部分類都是 NSObject 類的子類,所以都繼承了 NSObject 的行為。(NSProxy 類時個例外,它是個抽象超類)
一些情況下,NSObject 類僅僅定義了完成某件事情的模板,并沒有提供所需要的代碼。例如-description方法,該方法返回類內(nèi)容的字符串表示,該方法主要用來調(diào)試程序。NSObject 類并不知道子類的內(nèi)容,所以它只是返回類的名字和對象的地址,NSObject 的子類可以重新實現(xiàn)。

還有一些 NSObject 的方法可以從 Runtime 系統(tǒng)中獲取信息,允許對象進行自我檢查。例如:

  • class方法返回對象的類;
  • isKindOfClass: 和 -isMemberOfClass: 方法檢查對象是否存在于指定的類的繼承體系中(是否是其子類或者父類或者當(dāng)前類的成員變量);
  • respondsToSelector: 檢查對象能否響應(yīng)指定的消息;
  • conformsToProtocol:檢查對象是否實現(xiàn)了指定協(xié)議類的方法;
  • methodForSelector: 返回指定方法實現(xiàn)的地址。

3、通過對 Runtime 庫函數(shù)的直接調(diào)用
Runtime 系統(tǒng)是具有公共接口的動態(tài)共享庫。頭文件存放于/usr/include/objc目錄下,這意味著我們使用時只需要引入objc/Runtime.h頭文件即可。

id

id 是一個參數(shù)類型,它是指向某個類的實例的指針。定義如下:

typedef struct objc_object *id;
struct objc_object { Class isa; }

以上定義,看到 objc_object結(jié)構(gòu)體包含一個isa 指針,根據(jù) isa 指針就可以找到對象所屬的類

Class

typedef struct objc_class *Class;

Class其實是指向objc_class結(jié)構(gòu)體的指針。objc_class的數(shù)據(jù)結(jié)構(gòu)如下:

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;

objc_class 可以看到,一個運行時類中關(guān)聯(lián)了它的父類指針、類名、成員變量、方法、緩存以及附屬的協(xié)議。

其中objc_ivar_listobjc_method_list分別是成員變量列表方法列表

// 成員變量列表
struct objc_ivar_list {
   int ivar_count                                           OBJC2_UNAVAILABLE;
#ifdef __LP64__
   int space                                                OBJC2_UNAVAILABLE;
#endif
   /* variable length structure */
   struct objc_ivar ivar_list[1]                            OBJC2_UNAVAILABLE;
}                                                            OBJC2_UNAVAILABLE;

// 方法列表
struct objc_method_list {
   struct objc_method_list *obsolete                        OBJC2_UNAVAILABLE;

   int method_count                                         OBJC2_UNAVAILABLE;
#ifdef __LP64__
   int space                                                OBJC2_UNAVAILABLE;
#endif
   /* variable length structure */
   struct objc_method method_list[1]                        OBJC2_UNAVAILABLE;
}

由此可見,我們可以動態(tài)修改 *methodList 的值來添加成員方法,這也是 Category 實現(xiàn)的原理,同樣解釋了 Category 不能添加屬性的原因。
objc_ivar_list 結(jié)構(gòu)體用來存儲成員變量的列表,而 objc_ivar 則是存儲了單個成員變量的信息;同理,objc_method_list 結(jié)構(gòu)體存儲著方法數(shù)組的列表,而單個方法的信息則由 objc_method 結(jié)構(gòu)體存儲。
值得注意的是,objc_class中也有一個isa指針,這說明Objc類本身也是一個對象。為了處理類和對象的關(guān)系,Runtime庫創(chuàng)建了一個Meta Class(元類)的東西,類對象所屬的類就叫元類。Meta Class 表述了類對象本身所具備的元數(shù)據(jù)。
我們所熟悉的類方法,就源自于 Meta Class。我們可以理解為類方法就是類對象的實例方法。每個僅有一個類對象,而每個類對象僅有一個與之相關(guān)的元類。

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

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

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