(轉(zhuǎn)載)Objective-C總Runtime的那點事兒(一)消息機制

原文地址:http://www.cocoachina.com/ios/20141018/9960.html

找工作,Objective-C中的Runtime是經(jīng)常被問到的一個問題,幾乎是面試大公司必問的一個問題。當然還有一些其他問題也幾乎必問,例 如:RunLoop,Block,內(nèi)存管理等。其他的問題如果有機會我會在其他文章中介紹。本篇文章主要介紹RunTime。
RunTime簡稱運行時。就是系統(tǒng)在運行的時候的一些機制,其中最主要的是消息機制。對于C語言,函數(shù)的調(diào)用在編譯的時候會決定調(diào)用哪個函數(shù)( C語言的函數(shù)調(diào)用請看這里 )。編譯完成之后直接順序執(zhí)行,無任何二義性。OC的函數(shù)調(diào)用成為消息發(fā)送。屬于動態(tài)調(diào)用過程。在編譯的時候并不能決定真正調(diào)用哪個函數(shù)(事實證明,在編 譯階段,OC可以調(diào)用任何函數(shù),即使這個函數(shù)并未實現(xiàn),只要申明過就不會報錯。而C語言在編譯階段就會報錯)。只有在真正運行的時候才會根據(jù)函數(shù)的名稱找 到對應的函數(shù)來調(diào)用。
那OC是怎么實現(xiàn)動態(tài)調(diào)用的呢?下面我們來看看OC通過發(fā)送消息來達到動態(tài)調(diào)用的秘密。假如在OC中寫了這樣的一個代碼:

[obj makeText];

其中obj是一個對象,makeText是一個函數(shù)名稱。對于這樣一個簡單的調(diào)用。在編譯時RunTime會將上述代碼轉(zhuǎn)化成

objc_msgSend(obj,@selector(makeText));

首先我們來看看obj這個對象,iOS中的obj都繼承于NSObject。

@interface NSObject <nsobject> {

    
Class isa  OBJC_ISA_AVAILABILITY;

}</nsobject>

在NSObjcet中存在一個Class的isa指針。然后我們看看Class:

typedef struct objc_class *Class;

struct objc_class {
Class isa; 
// 指向metaclass
Class super_class ; 
// 指向其父類
const char *name ; 
// 類名
long version ; 
// 類的版本信息,初始化默認為0,可以通過runtime函數(shù)class_setVersion和class_getVersion進行修改、讀取
long info; 
// 一些標識信息,如CLS_CLASS (0x1L) 表示該類為普通 class ,其中包含對象方法和成員變量;CLS_META (0x2L) 表示該類為 metaclass,其中包含類方法;
long instance_size ; 
// 該類的實例變量大小(包括從父類繼承下來的實例變量);
struct objc_ivar_list *ivars; 
// 用于存儲每個成員變量的地址
struct objc_method_list **methodLists ; 
// 與 info 的一些標志位有關(guān),如CLS_CLASS (0x1L),則存儲對象方法,如CLS_META (0x2L),則存儲類方法; 
struct objc_cache *cache; 
// 指向最近使用的方法的指針,用于提升效率;  
struct objc_protocol_list *protocols; 
// 存儲該類遵守的協(xié)議    
}

我們可以看到,對于一個Class類中,存在很多東西,下面我來一一解釋一下:
Class isa:指向metaclass,也就是靜態(tài)的Class。一般一個Obj對象中的isa會指向普通的Class,這個Class中存儲普通成員變量和對 象方法(“-”開頭的方法),普通Class中的isa指針指向靜態(tài)Class,靜態(tài)Class中存儲static類型成員變量和類方法(“+”開頭的方 法)。
Class super_class:指向父類,如果這個類是根類,則為NULL。
下面一張圖片很好的描述了類和對象的繼承關(guān)系:

1413628797629491.png
1413628797629491.png

注意:所有metaclass中isa指針都指向跟metaclass。而跟metaclass則指向自身。Root metaclass是通過繼承Root class產(chǎn)生的。與root class結(jié)構(gòu)體成員一致,也就是前面提到的結(jié)構(gòu)。不同的是Root metaclass的isa指針指向自身。
Class類中其他的成員這里就先不做過多解釋了,下面我們來看看:
@selector (makeText):這是一個SEL方法選擇器。SEL其主要作用是快速的通過方法名字(makeText)查找到對應方法的函數(shù)指針,然后調(diào)用其函 數(shù)。SEL其本身是一個Int類型的一個地址,地址中存放著方法的名字。對于一個類中。每一個方法對應著一個SEL。所以iOS類中不能存在2個名稱相同 的方法,即使參數(shù)類型不同,因為SEL是根據(jù)方法名字生成的,相同的方法名稱只能對應一個SEL。
下面我們就來看看具體消息發(fā)送之后是怎么來動態(tài)查找對應的方法的。
首先,編譯器將代碼[obj makeText];轉(zhuǎn)化為objc_msgSend(obj, @selector (makeText));,在objc_msgSend函數(shù)中。首先通過obj的isa指針找到obj對應的class。在Class中先去cache中 通過SEL查找對應函數(shù)method(猜測cache中method列表是以SEL為key通過hash表來存儲的,這樣能提高函數(shù)查找速度),若 cache中未找到。再去methodList中查找,若methodlist中未找到,則取superClass中查找。若能找到,則將method加 入到cache中,以方便下次查找,并通過method中的函數(shù)指針跳轉(zhuǎn)到對應的函數(shù)中去執(zhí)行。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容