RunTime簡(jiǎn)稱(chēng)運(yùn)行時(shí)蒿褂。就是系統(tǒng)在運(yùn)行的時(shí)候的一些機(jī)制监嗜,其中最主要的是消息機(jī)制非迹。對(duì)于C語(yǔ)言毕泌,函數(shù)的調(diào)用在編譯的時(shí)候會(huì)決定調(diào)用哪個(gè)函數(shù)( C語(yǔ)言的函數(shù)調(diào)用請(qǐng)看這里 )喝检。編譯完成之后直接順序執(zhí)行,無(wú)任何二義性撼泛。OC的函數(shù)調(diào)用成為消息發(fā)送蛇耀。屬于動(dòng)態(tài)調(diào)用過(guò)程。在編譯的時(shí)候并不能決定真正調(diào)用哪個(gè)函數(shù)(事實(shí)證明坎弯,在編 譯階段纺涤,OC可以調(diào)用任何函數(shù),即使這個(gè)函數(shù)并未實(shí)現(xiàn)抠忘,只要申明過(guò)就不會(huì)報(bào)錯(cuò)撩炊。而C語(yǔ)言在編譯階段就會(huì)報(bào)錯(cuò))。只有在真正運(yùn)行的時(shí)候才會(huì)根據(jù)函數(shù)的名稱(chēng)找 到對(duì)應(yīng)的函數(shù)來(lái)調(diào)用崎脉。
[obj makeText];
其中obj是一個(gè)對(duì)象拧咳,makeText是一個(gè)函數(shù)名稱(chēng)。對(duì)于這樣一個(gè)簡(jiǎn)單的調(diào)用囚灼。在編譯時(shí)RunTime會(huì)將上述代碼轉(zhuǎn)化成
objc_msgSend(obj,@selector(makeText));
首先我們來(lái)看看obj這個(gè)對(duì)象骆膝,iOS中的obj都繼承于NSObject祭衩。
@interface NSObject <nsobject> {
Class isa OBJC_ISA_AVAILABILITY;
}</nsobject>
在NSObjcet中存在一個(gè)Class的isa指針。然后我們看看
Class:
typedef struct objc_class *Class;
struct objc_class {
Class isa; // 指向metaclass
Class super_class ; // 指向其父類(lèi)
const char *name ; // 類(lèi)名
long version ; // 類(lèi)的版本信息阅签,初始化默認(rèn)為0掐暮,可以通過(guò)runtime函數(shù)class_setVersion和class_getVersion進(jìn)行修改、讀取
long info; // 一些標(biāo)識(shí)信息,如CLS_CLASS (0x1L) 表示該類(lèi)為普通 class 政钟,其中包含對(duì)象方法和成員變量;CLS_META (0x2L) 表示該類(lèi)為 metaclass路克,其中包含類(lèi)方法;
long instance_size ; // 該類(lèi)的實(shí)例變量大小(包括從父類(lèi)繼承下來(lái)的實(shí)例變量);
struct objc_ivar_list *ivars; // 用于存儲(chǔ)每個(gè)成員變量的地址
struct objc_method_list **methodLists ; // 與 info 的一些標(biāo)志位有關(guān),如CLS_CLASS (0x1L),則存儲(chǔ)對(duì)象方法,如CLS_META (0x2L)养交,則存儲(chǔ)類(lèi)方法;
struct objc_cache *cache; // 指向最近使用的方法的指針精算,用于提升效率;
struct objc_protocol_list *protocols; // 存儲(chǔ)該類(lèi)遵守的協(xié)議
}
我們可以看到碎连,對(duì)于一個(gè)Class類(lèi)中灰羽,存在很多東西,下面我來(lái)一一解釋一下:
Class isa:指向metaclass鱼辙,也就是靜態(tài)的Class谦趣。一般一個(gè)Obj對(duì)象中的isa會(huì)指向普通的Class,這個(gè)Class中存儲(chǔ)普通成員變量和對(duì) 象方法(“-”開(kāi)頭的方法)座每,普通Class中的isa指針指向靜態(tài)Class前鹅,靜態(tài)Class中存儲(chǔ)static類(lèi)型成員變量和類(lèi)方法(“+”開(kāi)頭的方 法)。
Class super_class:指向父類(lèi)峭梳,如果這個(gè)類(lèi)是根類(lèi)舰绘,則為NULL。
注意:所有metaclass中isa指針都指向跟metaclass葱椭。而跟metaclass則指向自身捂寿。Root metaclass是通過(guò)繼承Root class產(chǎn)生的。與root class結(jié)構(gòu)體成員一致孵运,也就是前面提到的結(jié)構(gòu)秦陋。不同的是Root metaclass的isa指針指向自身。
Class類(lèi)中其他的成員這里就先不做過(guò)多解釋了治笨,下面我們來(lái)看看:
@selector (makeText):這是一個(gè)SEL方法選擇器驳概。SEL其主要作用是快速的通過(guò)方法名字(makeText)查找到對(duì)應(yīng)方法的函數(shù)指針,然后調(diào)用其函 數(shù)旷赖。SEL其本身是一個(gè)Int類(lèi)型的一個(gè)地址顺又,地址中存放著方法的名字。對(duì)于一個(gè)類(lèi)中等孵。每一個(gè)方法對(duì)應(yīng)著一個(gè)SEL稚照。所以iOS類(lèi)中不能存在2個(gè)名稱(chēng)相同 的方法,即使參數(shù)類(lèi)型不同,因?yàn)镾EL是根據(jù)方法名字生成的果录,相同的方法名稱(chēng)只能對(duì)應(yīng)一個(gè)SEL上枕。
下面我們就來(lái)看看具體消息發(fā)送之后是怎么來(lái)動(dòng)態(tài)查找對(duì)應(yīng)的方法的。
首先弱恒,編譯器將代碼[obj makeText];轉(zhuǎn)化為objc_msgSend(obj, @selector (makeText));辨萍,在objc_msgSend函數(shù)中。首先通過(guò)obj的isa指針找到obj對(duì)應(yīng)的class斤彼。在Class中先去cache中 通過(guò)SEL查找對(duì)應(yīng)函數(shù)method(猜測(cè)cache中method列表是以SEL為key通過(guò)hash表來(lái)存儲(chǔ)的分瘦,這樣能提高函數(shù)查找速度)蘸泻,若 cache中未找到琉苇。再去methodList中查找,若methodlist中未找到悦施,則取superClass中查找并扇。若能找到,則將method加 入到cache中抡诞,以方便下次查找穷蛹,并通過(guò)method中的函數(shù)指針跳轉(zhuǎn)到對(duì)應(yīng)的函數(shù)中去執(zhí)行。