Objective-C--Runtime機制

我的理解:

簡單來講,Objective-C runtime是一個實現Objective-C語言的C庫。對象能夠用C語言中的結構體表示,而方法(methods)能夠用C函數實現。事實上,他們 差很少也是這麼幹了,另外再加上了一些額外的特性。這些結構體和函數被runtime函數封裝後,Objective-C程序員能夠在程序運行時建立,檢 查,修改類,對象和它們的方法。例如一個普通類,咱們寫好以後,Runtime會進行處理。最後變成如下結構:html

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;

經過一個結構體的方式,來存放類中的信息。ios

再好比,咱們調用的實例方法。從本質上來看是用C語言中的函數來實現的,可是在外面咱們仍是對實例方法使用結構體進行了封裝。結構體以下:git

struct objc_method {
    SEL method_name                                          OBJC2_UNAVAILABLE;//函數名
    char *method_types                                       OBJC2_UNAVAILABLE;//method_types是個char指針,存儲着方法的參數類型和返回值類型。
    IMP method_imp                                           OBJC2_UNAVAILABLE;//函數指針,指向這個函數的首地址
}

在重複一下,Objective-C runtime是一個實現Objective-C語言的C庫。程序員


幾個知識點的簡要概述:

Object & Class & Meta Class

什麼是Object?

在oc中有一個id的概念。他的定義爲:github

typedef struct objc_object *id;

struct objc_object {
    Class isa;
};

Objective-C中的object在最後會被轉換成C的結構體,而在這個struct中有一個 isa 指針,指向它的類別 Class。objective-c

什麼是Class?

typedef struct objc_class *Class;

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;

上面是類在runtime中的源代碼,從這看,類其實也是一個結構體。這個結構體中的isa指向一個Metaclass。數組

什麼是Metaclass?

仔細一看,發現 Class isa,原來,isa(Metaclass)的源碼仍是類的源碼:markdown

typedef struct objc_class *Class;

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;

Object, Class, MetaClass三者之間的關係?

  • Class存放類信息,方法數組存放實例方法;Meta Class存放類信息,方法數組存放類方法。函數

  • 每個object都有一個isa指針,isa指針指向本身的Class 每一個Class都有一個isa指針指向一個惟一的Meta Classui

  • 每個Meta Class的isa指針都指向最上層的Meta Class(圖中的NSObject的Meta Class) 最上層的Meta
  • Class的isa指針指向本身,造成一個迴路 每個Meta Class的super class指針指向它本來Class的 Super
  • Class的Meta Class。可是最上層的Meta Class的 Super Class指向NSObject Class自己
  • 最上層的NSObject Class的super class指向 nil

objective-C中的消息機制?

什麼是SEL?

typedef struct objc_selector *SEL;

SEL是一個指向objc_selector結構體的指針。而 objc_selector 的定義並無在runtime.h中給出定義。
編譯器會根據每一個方法的方法名爲那個方法生成惟一的SEL。只要方法名相同,那麼它的SEL就是同樣的。每個方法都對應着一個SEL。

什麼是IMP?

typedef id (*IMP)(id, SEL, …);

IMP本質就是一個函數指針,這個被指向的函數包含一個接收消息的對象id,調用方法的SEL,以及一些方法參數,並返回一個id。所以咱們能夠經過SEL得到它所對應的IMP,在取得了函數指針以後,也就意味着咱們取得了須要執行方法的代碼入口,這樣咱們就能夠像普通的C語言函數調用同樣使用這個函數指針。

類中的方法存儲?

什麼是方法?

typedef struct objc_method *Method;

struct objc_method { SEL method_name OBJC2_UNAVAILABLE; char *method_types OBJC2_UNAVAILABLE; IMP method_imp OBJC2_UNAVAILABLE; }                                                            OBJC2_UNAVAILABLE;

方法存放位置?

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;                                                        OBJC2_UNAVAILABLE;

在建立一個類的時候,咱們將類中的實例方法存放到objc_class結構體(類的結構體,前面提到)中的objc_method_list **methodLists中。將類中的類方法存放到相應的MetaClass中的類結構中的objc_method_list **methodLists中。咱們能夠理解爲objc_class中 method list保存了一組SEL<->IMP的映射。

調用方法的具體步驟?

在Objective-C中,消息直到運行時纔會綁定到方法的實現上。編譯器會把代碼中[target doSth]轉換成 objc_msgSend消息函數,這個函數完成了動態綁定的全部事情。它的運行流程以下:

  • 檢查selector是否須要忽略。(ps: Mac開發中開啓GC就會忽略retain,release方法。)
  • 檢查target是否爲nil。若是爲nil,直接cleanup,而後return。(這就是咱們能夠向nil發送消息的緣由。)
  • 而後在target的Class中根據Selector去找IMP

尋找IMP的過程:

objective-C中的Category?

看Category的源碼,不用想就知道這個又是一個結構體

typedef struct objc_category *Category;

struct objc_category {
    char *category_name                                      OBJC2_UNAVAILABLE;//分類名
    char *class_name                                         OBJC2_UNAVAILABLE;//類名
    struct objc_method_list *instance_methods                OBJC2_UNAVAILABLE;//實例方法列表
    struct objc_method_list *class_methods                   OBJC2_UNAVAILABLE;//類方法列表
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;//協議列表
}

運行過程:

  • 加載Category
  • 將Category加載到所屬的類中
  • 將Category中的方法加載到Class或者MetaClass結構體中的方法列表中
    (具體看這裏的運行代碼)

objective-C中的成員變量與屬性?

什麼是成員變量?

typedef struct objc_ivar *Ivar;

struct objc_ivar {
    char *ivar_name                                          OBJC2_UNAVAILABLE;
    char *ivar_type                                          OBJC2_UNAVAILABLE;
    int ivar_offset                                          OBJC2_UNAVAILABLE;
#ifdef __LP64__
    int space                                                OBJC2_UNAVAILABLE;
#endif
}

這裏咱們注意第三個成員 ivar_offset。它表示基地址偏移字節。咱們經過字節偏移量來獲取變量的地址。(具體方式不展開)

成員變量存放位置?

存放在以前咱們彷彿強調的objc_class中的struct objc_ivar_list *ivars中 。

屬性和成員變量的區別?

類中的Property屬性被編譯器轉換成了Ivar,而且自動添加了咱們熟悉的Set和Get方法。


講解Runtime,結合代碼和題目

http://www.cocoachina.com/ios/20141224/10740.html
刨根問底Objective-C Runtime(1)- Self & Super
刨根問底Objective-C Runtime(2)- Object & Class & Meta Class
刨根問底Objective-C Runtime(3)- 消息和Category
刨根問底Objective-C Runtime(4)- 成員變量與屬性

這一系列文章中,講的很全面,可是沒有結合源代碼具體來看

Objective-C Runtime 運行時之一:類與對象

Objective-C Runtime 運行時之二:成員變量與屬性

Objective-C Runtime 運行時之三:方法與消息

Objective-C Runtime 運行時之四:Method Swizzling

Objective-C Runtime 運行時之五:協議與分類

Objective-C Runtime 運行時之六:拾遺