前言
最近在對ios做一下總結(jié),一直想寫一些關于Rumtime的東西了版述,實際開發(fā)中用到的比較多的場景梯澜,但是相對來說,一般的項目也沒有用到。
- 動態(tài)改變方法的執(zhí)行體
- Method Swizzling
- NSSelectorFromString晚伙,NSClassFromString…
- 動態(tài)添加屬性(主要是類別)
- 動態(tài)遍歷屬性和方法吮龄,動態(tài)為類添加方法
但是,基本的概念很重要咆疗,計劃Runtime這個系列計劃幾篇文章
- 講講一些基本概念(本文)漓帚,例如SEL,Class午磁,id尝抖,IMP等等
- 詳解iOS 中消息的傳遞機制,以及消息轉(zhuǎn)發(fā)機制迅皇,內(nèi)存分配昧辽,類對象,類元對象
- Method Swizzling
- 其他常見實際應用
什么是Runtime登颓?
objective C語言把能在編譯期做的事情就推遲到運行期再決定搅荞。這就意味著,Objective C不僅需要一個編譯器框咙,而且需要一個運行期環(huán)境咕痛。這個運行期環(huán)境就是Runtime。
我們來看一下喇嘱,最直接的例子就是方法調(diào)用 茉贡,這樣的一個OC方法
[receiver message]
會被編譯成
objc_msgSend(receiver, selector)
這里,先記著receiver就是接受消息的對象婉称,selector是執(zhí)行消息的函數(shù)體名稱,是個C的字符串块仆。而不是像其他語言一樣,直接編譯成一個指向函數(shù)體的指針王暗。
那么悔据,在運行的時候,如何通過objc_msgSend(receiver, selector)找到實際的函數(shù)體呢俗壹?
記得最開始接觸Runtime的時候科汗,感覺很亂,基本上看不懂绷雏,經(jīng)過多次的研究和看別人寫的技術文章头滔,感覺還是要把里面的一些重要的名字的含義理解清楚,知道每個都是什么意思涎显,要表達什么坤检,搞不清楚這些名詞是幾乎不可能深入理解和應用Runtime的。
所以期吓,我講解Runtime的方式是早歇,先搞清楚一些基本的關鍵詞的底層定義,然后講解消息處理以及轉(zhuǎn)發(fā)機制,最后講解示例箭跳。
SEL/objc_selector
objc_selector
可以理解為C語言的 String
SEL
源代碼定義
typedef struct objc_selector *SEL;
也就是說晨另,SEL是指向一個C String的指針。
id/objc_object
id - 指向一個類的實例對象
底層代碼定義
typedef struct objc_object *id;
其中
objc_object的底層定義
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
可以看到谱姓,objc_object中借尿,只是保存了一個Class類型的isa。這里看不懂不要怕屉来,先記著路翻,對象中就是保存了一個指向Objective C中對應類的指針。
Class/objc_class
Class - 指向Objective C類對象(objc_class)的一個指針
底層定義
typedef struct objc_class *Class;
objc_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;
/* Use `Class` instead of `struct objc_class *` */
可以看到奶躯,這就是類對象結(jié)構體的定義帚桩,細心的同學可能發(fā)現(xiàn)了類對象里仍然有一個指針Class isa,先記著嘹黔,這個isa指向的是類元對象账嚎。這個我會在下一篇文章里詳細闡述
IMP
IMP-指向?qū)嶋H執(zhí)行函數(shù)體的函數(shù)指針
#if !OBJC_OLD_DISPATCH_PROTOTYPES
typedef void (*IMP)(void /* id, SEL, ... */ );
#else
typedef id (*IMP)(id, SEL, ...);
#endif
可以看到,這個函數(shù)體前兩個參數(shù)是 id(消息接受者儡蔓,也就是對象)郭蕉,以及SEL(方法的名字)
method/objc_method
method - 指向Objective C中的方法的指針
typedef struct objc_method *Method;
其中
struct objc_method {
SEL method_name OBJC2_UNAVAILABLE;
char *method_types OBJC2_UNAVAILABLE;
IMP method_imp OBJC2_UNAVAILABLE;
}
_cmd
SEL 類型的一個變量,Objective C的函數(shù)的前兩個隱藏參數(shù)為self 和 _cmd
Ivar
ivar - objective C中的實例變量
typedef struct objc_ivar *Ivar;
可以看到變量的內(nèi)存模型
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
} OBJC2_UNAVAILABLE;