Objective-C是從C發(fā)展出來的語言,只是在語言層面上加了些關(guān)鍵字和語法。真正讓Objective-C強大的是它的Runtime運行時,讓OC在C語言的基礎上增加了面向?qū)ο蠛蛣討B(tài)特性。
Q1:OC與C語言有什么不同?
C是靜態(tài)語言、面向過程語言
OC是動態(tài)語言、面向?qū)ο笳Z言
因此,OC更加強大。
Q2:C是靜態(tài)語言,OC是從C語言發(fā)展出來的,OC如何實現(xiàn)動態(tài)的?
Runtime(運行時)
Q3:什么是Runtime?
- Runtime是為了實現(xiàn) OC 面向?qū)ο蟆討B(tài)機制的一個庫。
- 由 C 和匯編語言寫成。
Q4:Runtime干什么?
OC代碼并不是直接編譯為目標語言,OC代碼首先需要編譯器轉(zhuǎn)化為純C語言,然后編譯和匯編成目標代碼。
其中,從OC到C語言的轉(zhuǎn)化,就需要運行時庫Runtime。這個運行時庫(Runtime)用來動態(tài)得創(chuàng)建類和對象、進行消息傳遞和轉(zhuǎn)發(fā)。
- 將 OC 面向?qū)ο蟮念愞D(zhuǎn)變?yōu)?C 語言面向過程的結(jié)構(gòu)體
- 將 OC 函數(shù)調(diào)用轉(zhuǎn)化為消息傳遞和轉(zhuǎn)發(fā)
- 消息傳遞和轉(zhuǎn)發(fā)的過程,最終找到合適的C函數(shù)執(zhí)行的過程。
Q5:如何實現(xiàn)Runtime?
Runtime核心是消息分發(fā)機制
Runtime一些核心結(jié)構(gòu)體定義
1. 對象定義:
struct objc_object {
Class isa;
} *id;
每個OC對象的首個成員是一個指向Class的指針isa(如果子類中定義了其他對象,那么追加在后面)。
2. Class定義:
typedef struct objc_class *Class;
Class就是一個指針,指向一個objc_class結(jié)構(gòu)體。
3. objc_class結(jié)構(gòu)體的定義:
struct objc_class {
Class isa; //指針:指向當前類的元類(類的類)
Class super_class; //指針:指向當前類的父類
const char *name;
long version;
long info;
long instance_size;
struct objc_ivar_list *ivars;
struct objc_method_list ** methodLists; //方法列表
struct objc_cache *cache; //cache的方法
struct objc_protocol_list *protocols;
};
- objc_class定義了類的信息,存放了類的元數(shù)據(jù)metadata,其中包括類的元類、父類、Name、變量、方法列表、方法cache(用于加速方法查詢)。
- objc_class類中首個變量也是一個isa指針,說明Class也是一個對象(類也是一個對象)。
- objc_class的isa指針指向的當前類的類(元類metaclass),保存了當前類對象的元數(shù)據(jù),類方法定義此處。
- 每個類僅有一個元類metaclass,每個元類僅有一個metaclass對象(就是這個類Class)

- 每個類對象中持有了一個isa指針,指向這個對象的類對象(類對象保存了該類的成員方法);
- 類對象中的super_class指針指向了這個類的父類,isa指向該類的元類(元類保存了該類的類方法);
- 元類中的super_class指針指向元類的父類。
4. 選擇器Selector
// An opaque type that represents a method selector.
typedef struct objc_selector *SEL;
選擇器Selector用于標識一個方法。從上面代碼中我們可以看出,SEL是一個指向objc_selector結(jié)構(gòu)體的指針。
struct objc_selector {
char *name;
char *types;
};
objc_selector是一個結(jié)構(gòu)體,用于標識一個方法。用于在類的HashTable找到對應的函數(shù)。
5. IMP
typedef void (*IMP)(void /* id, SEL, ... */ );
IMP就是一個函數(shù)指針,參數(shù)為(id, SEL, ...) 指向函數(shù)所在內(nèi)存地址
6. 方法列表
struct objc_method {
SEL _Nonnull method_name ;
char * method_types;
IMP _Nonnull method_imp ;
};
typedef struct objc_method *Method;
struct objc_method_list {
struct objc_method_list *bsolete;
int method_count;
/* variable length structure */
struct objc_method method_list[1];
};
objc_method結(jié)構(gòu)體保存方法的信息,其中包含SEL和IMP,SEL用來標識一個方法,IMP用來指向方法的內(nèi)存地址。
7. 方法緩存
struct objc_cache {
unsigned int mask /* total = mask + 1 */ ;
unsigned int occupied;
Method _Nullable buckets[1];
};
當 objc_msgSend() 通過一個類來查找一個選擇器SEL時,它首先會搜索類緩存,用于快速查找Method,如果沒找到再遍歷objc_method_list。
8. 變量列表
struct objc_ivar {
char * ivar_name;
char * ivar_type;
int ivar_offset ;
};
struct objc_ivar_list {
int ivar_count;
/* variable length structure */
struct objc_ivar ivar_list[1];
};
9. 協(xié)議列表
struct objc_protocol_list {
struct objc_protocol_list * next;
long count;
__unsafe_unretained Protocol * list[1];
};
@interface Protocol : NSObject
@end
Protocol也是一個對象。
從上面可以看出:
- Class、SEL、Method都是指向特定結(jié)構(gòu)體的指針。
- IMP是函數(shù)指針。
小結(jié):本文簡單介紹了iOS Runtime的一些基本概念,并分析了runtime的源碼中這些概念的實現(xiàn)。
簡單來說OC在C語言的基礎上定義了一系列的概念(如Class、SEL、Method、IMP),引入了面向?qū)ο?、消息傳遞和轉(zhuǎn)發(fā)機制,從而實現(xiàn)了Runtime機制。
參考:
Runtime 源碼