提前聲明:本系列文章的objc源碼是基于objc-723源碼的杀餐。不同的版本裙盾,可能都有所不同,但相信除了部分語法及機(jī)制上的變更郎任,不會(huì)有本質(zhì)的差別秧耗。
關(guān)于Objc的運(yùn)行時(shí)原理及消息機(jī)制,對(duì)于做iOS開發(fā)的人舶治,或多或少都有所接觸分井。然而,由于這部分知識(shí)在我們的項(xiàng)目中使用的頻率實(shí)在太低霉猛。因此尺锚,對(duì)于大多數(shù)從事iOS開發(fā)的人而言是學(xué)而不精。即便惜浅,我們?cè)啻位仡欉@些知識(shí)瘫辩。可能真到某一節(jié)點(diǎn)坛悉,還是會(huì)從頭來復(fù)習(xí)一邊伐厌,以增進(jìn)理解÷阌埃可是挣轨,到目前為止,并沒有一份很好的資料來體系化的介紹關(guān)于Objc的源碼空民。
今天刃唐,我們就開始我們這一系列教材的第一篇,讀objc.h文件界轩。
為什么画饥,要從這個(gè)文件開始呢?很簡單浊猾,我們平日里做Objc開發(fā)時(shí)抖甘,最基本最直接的就放在這個(gè)文件里了。
打開文件葫慎,忽略掉引入的頭文件和一些非關(guān)鍵信息衔彻,我們看到的第一條語句是:
typedef struct objc_class *Class;
這就是我們平日里用到的Class類型了薇宠。而緊隨其后的是Objc面向?qū)ο缶幊讨校瑢?shí)例的結(jié)構(gòu)表示的定義:
struct objc_object {
? ? Class _Nonnull isa? OBJC_ISA_AVAILABILITY;
};
typedef struct objc_object *id;
id即是我們平日里用的比較多的Objc對(duì)象的一個(gè)類型表示艰额。
接下來澄港,則是我們常用的SEL:
typedef struct objc_selector *SEL;
之后即是我們平日不常用,也不常見柄沮,但對(duì)Objc的整個(gè)方法調(diào)用機(jī)制極為重要的IMP了:
#if !OBJC_OLD_DISPATCH_PROTOTYPES
typedef void (*IMP)(void /* id, SEL, ... */ );
?#else
typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...);?
#endif
緊接著往下回梧,是對(duì)BOOL及其對(duì)應(yīng)的值YES與NO的定義和對(duì)Nil與nil的定義。在這里要強(qiáng)調(diào)一下祖搓,從源碼的角度來講狱意,Nil與nil在定義上是完全一樣的,兩者的用途也沒有嚴(yán)格的要求拯欧,也就是說详囤,兩者本質(zhì)上是可以通用的,但是镐作,還是建議我們按章通常的約定用Nil表示空類藏姐,用nil表示對(duì)空象。至于為什么這么說滑肉,原因很多包各,就不細(xì)說了。當(dāng)然靶庙,如果你硬要將兩者用到混用问畅,其實(shí)誰也無法阻止,畢竟最后及其都會(huì)將二者識(shí)別為相同的東西六荒。
再繼續(xù)往下护姆,則是對(duì)非ARC(或稱MRC)機(jī)制下的關(guān)于引用計(jì)數(shù)內(nèi)存管理相關(guān)的參數(shù)的保護(hù)性定義。這包括__strong掏击,__unsafe_unretained卵皂,__autoreleasing。
繼續(xù)往下看砚亭,定義的是幾個(gè)與函數(shù)或方法名操作相關(guān)的:
OBJC_EXPORT const char * _Nonnull sel_getName(SEL _Nonnull sel) OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
OBJC_EXPORT SEL _Nonnull sel_registerName(const char * _Nonnull str) OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
OBJC_EXPORT const char * _Nonnull object_getClassName(id _Nullableobj) OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
OBJC_EXPORT void* _Nullable object_getIndexedIvars(id _Nullable obj) OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0) OBJC_ARC_UNAVAILABLE;
OBJC_EXPORT BOOL sel_isMapped(SEL _Nonnull sel) OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
OBJC_EXPORT SEL _Nonnull sel_getUid(const char * _Nonnull str) OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
緊接著的幾個(gè)操作都是針對(duì)內(nèi)存引用技術(shù)的操作灯变,在當(dāng)前版本下已經(jīng)被廢棄。但是捅膘,這并不意味著這對(duì)我們就不重要了添祸。因?yàn)橄旅娴膸讉€(gè)操作在比較老的版本中,對(duì)內(nèi)存管理是比較重要的寻仗。只是隨著objc版本的不斷迭代改進(jìn)刃泌,而在當(dāng)前的版本廢棄了而已,不過言歸正傳,對(duì)這幾個(gè)操作的了解可以幫我們加深對(duì)內(nèi)存管理的理解耙替,但是在實(shí)際應(yīng)用場景中亚侠,我們基本上沒用直接用過。
typedef const void* objc_objectptr_t;
OBJC_EXPORT id _Nullable objc_retainedObject(objc_objectptr_t _Nullable obj) OBJC_UNAVAILABLE("use CFBridgingRelease() or a (__bridge_transfer id) cast instead");
OBJC_EXPORT id _Nullable objc_unretainedObject(objc_objectptr_t _Nullable obj) OBJC_UNAVAILABLE("use a (__bridge id) cast instead");
OBJC_EXPORT objc_objectptr_t _Nullable objc_unretainedPointer(id _Nullable obj) OBJC_UNAVAILABLE("use a __bridge cast instead");
最后俗扇,是基于基本類型聲明的幾個(gè)有意義的別名及對(duì)上面部分函數(shù)的簡化宏定義硝烂。到這一步,我們?cè)谌粘5腛bjc工作中狐援,常用到的Class钢坦,id, SEL, 及IMP都已經(jīng)展示在了我們面前。同時(shí)我們也應(yīng)該關(guān)心一下Nil與nil啥酱,盡量不要將二者不加區(qū)分混用。這片文章厨诸,到此結(jié)束镶殷。在后續(xù)的文章中,我們將以這邊文章的內(nèi)容為點(diǎn)不斷地進(jìn)行擴(kuò)散微酬。