雖然swift 慢慢會(huì)越用越多,但憑借oc 強(qiáng)大的runtime機(jī)制,oc依舊是現(xiàn)在的中流砥柱.只做記錄探討 加深自己的理解.runTime簡稱運(yùn)行時(shí)柑营。就是系統(tǒng)在運(yùn)行的時(shí)候的一些機(jī)制,其中最主要的是消息機(jī)制村视。對于C語言官套,函數(shù)的調(diào)用在編譯的時(shí)候會(huì)決定調(diào)用哪個(gè)函數(shù)( C語言的函數(shù)調(diào)用請看這里 )。編譯完成之后直接順序執(zhí)行蚁孔,無任何二義性奶赔。OC的函數(shù)調(diào)用成為消息發(fā)送。屬于動(dòng)態(tài)調(diào)用過程勒虾。在編譯的時(shí)候并不能決定真正調(diào)用哪個(gè)函數(shù)(事實(shí)證明纺阔,在編 譯階段,OC可以調(diào)用任何函數(shù)修然,即使這個(gè)函數(shù)并未實(shí)現(xiàn)笛钝,只要申明過就不會(huì)報(bào)錯(cuò)质况。而C語言在編譯階段就會(huì)報(bào)錯(cuò))。只有在真正運(yùn)行的時(shí)候才會(huì)根據(jù)函數(shù)的名稱找 到對應(yīng)的函數(shù)來調(diào)用玻靡。
那OC是怎么實(shí)現(xiàn)動(dòng)態(tài)調(diào)用的呢结榄?下面我們來看看OC通過發(fā)送消息來達(dá)到動(dòng)態(tài)調(diào)用的秘密。假如在OC中寫了這樣的一個(gè)代碼:
[obj ? ? xMethod]
其中obj是一個(gè)對象囤捻,xMethod是一個(gè)函數(shù)名稱臼朗。對于這樣一個(gè)簡單的調(diào)用。在編譯時(shí)RunTime會(huì)將上述代碼轉(zhuǎn)化成
objc_msgSend(obj,@selrctor(xMethod));
首先我們先看下obj這個(gè)對象,ios中的obj都繼承于NSObject
@interface NSObject <nsobject>{
? ? Class isa ?OBJC_ISA_AVAILABILITY;
}</nsobjct>
在NSObject中存在一個(gè)Class的isa指針蝎土。然后我們看看Class:
typedef struct objc_class *Class;
struct objc_class {
Class isa? OBJC_ISA_AVAILABILITY;//指向metaclass
#if !__OBJC2__
Class super_class? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OBJC2_UNAVAILABLE;
//指向父類
const char *name? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OBJC2_UNAVAILABLE;
//類名
long version? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OBJC2_UNAVAILABLE;
//類的版本信息,初始化默認(rèn)為0,可通過runtime函數(shù)class_setVersion和class_getVersion進(jìn)行修改视哑、讀取
long info? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OBJC2_UNAVAILABLE;
//一些標(biāo)識(shí)信息,如CLS_CLASS(0x1L)表示該類為普通class,其中包含對象方法和成員變量;CLS_META(0x2L)表示該類為metaclass,其中包含類方法;
long instance_size? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OBJC2_UNAVAILABLE;
//該類的實(shí)例變量大小(包含從父類繼承下來的實(shí)例變量)
struct objc_ivar_list *ivars? ? ? ? ? ? ? ? ? ? ? ? ? ? OBJC2_UNAVAILABLE;
//用于存儲(chǔ)每個(gè)成員變量的地址
struct objc_method_list **methodLists? ? ? ? ? ? ? ? ? ? OBJC2_UNAVAILABLE;
//與 info 的一些標(biāo)志位有關(guān),如CLS_CLASS (0x1L),則存儲(chǔ)對象方法,如CLS_META (0x2L)誊涯,則存儲(chǔ)類方法;
struct objc_cache *cache? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? OBJC2_UNAVAILABLE;
//指向最近使用的方法的指針,用于提升效率
struct objc_protocol_list *protocols? ? ? ? ? ? ? ? ? ? OBJC2_UNAVAILABLE;
//存儲(chǔ)該類遵守的協(xié)議.
#endif
} OBJC2_UNAVAILABLE;
我們可以看到,對于一個(gè)Class類中挡毅,存在很多東西,下面來一一解釋下
Class isa:指向metaclass,也就是說靜態(tài)的Class.一般一個(gè)obj對象中的isa會(huì)指向普通的Class暴构,這個(gè)Class中存儲(chǔ)普通成員變量和對象方法("-"開頭的方法),普通Class中的isa指針指向靜態(tài)Class,靜態(tài)Class中存儲(chǔ)static類型成員變量和類方法("+"開頭的方法)跪呈。
Class super_class:指向父類,如果這個(gè)類是根類取逾,則為NULL耗绿。
下面的一張圖片很好的描述了類和對象的關(guān)系
注意:所有metaclass中isa指針都指向根metaclass.而根metaclass則指向自身。Root metaclass是通過繼承Root class產(chǎn)生的砾隅。與root class結(jié)構(gòu)體成員一致误阻,也就是前面提到的結(jié)構(gòu)。不同的是Root metaclass的isa指針指向自身琉用。
Class類中其他的成員這里就先不做過多解釋了堕绩,下面我們看看
@selector(xMethod):這是一個(gè)SEL方法選擇器。SEL其主要是快速的通過方法名字(xMethod)查找到對應(yīng)方法的函數(shù)指針邑时,然后調(diào)用其函數(shù)。SEL其本身是一個(gè)int類型的一個(gè)地址特姐,地址中存放著方法的名字晶丘。對于一個(gè)類中。每一個(gè)方法對應(yīng)著一個(gè)SEL唐含。所以iOS類中不能存在2個(gè)名稱相同 的方法浅浮,即使參數(shù)類型不同,因?yàn)镾EL是根據(jù)方法名字生成的捷枯,相同的方法名稱只能對應(yīng)一個(gè)SEL滚秩。
下面我們就來看看具體消息發(fā)送之后是怎么來動(dòng)態(tài)查找對應(yīng)的方法的。
首先淮捆,編譯器將代碼[obj xMethod] 轉(zhuǎn)化為[objc_msgSend(obj,@selector(xMethod))];在objc_msgSend函數(shù)中郁油。首先通過obj的isa指針找到obj對應(yīng)的class本股。在class中先去cache中通過SEL查找對應(yīng)函數(shù)method,若cache中未找到。再去methodList中查找桐腌,若methodist中未找到拄显,則取superclass中查找。若能找到案站,則將method加入到cache中躬审,以方便下次查找,并通過method中的函數(shù)指針跳轉(zhuǎn)到對應(yīng)的函數(shù)中去執(zhí)行蟆盐。