簡單來講,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庫。程序員
在oc中有一個id的概念。他的定義爲:github
typedef struct objc_object *id;
struct objc_object {
Class isa;
};
Objective-C中的object在最後會被轉換成C的結構體,而在這個struct中有一個 isa 指針,指向它的類別 Class。objective-c
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。數組
仔細一看,發現 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;
Class存放類信息,方法數組存放實例方法;Meta Class存放類信息,方法數組存放類方法。函數
每個object都有一個isa指針,isa指針指向本身的Class 每一個Class都有一個isa指針指向一個惟一的Meta Classui
typedef struct objc_selector *SEL;
SEL是一個指向objc_selector結構體的指針。而 objc_selector 的定義並無在runtime.h中給出定義。
編譯器會根據每一個方法的方法名爲那個方法生成惟一的SEL。只要方法名相同,那麼它的SEL就是同樣的。每個方法都對應着一個SEL。
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消息函數,這個函數完成了動態綁定的全部事情。它的運行流程以下:
尋找IMP的過程:
看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;//協議列表
}
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方法。
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