Objective-C是基於C語言加入了面向對象特性和消息轉發機制的動態語言,這意味著它不僅需要一個編譯器,還需要Runtime系統來動態創建類和對象,進行消息發送和轉發。下面通過分析Apple開源的Runtime代碼(我使用的版本是objc4-646.tar)來深入理解Objective-C的Runtime機制。
在Objective-C中,使用[receiver message]語法並不會馬上執行receiver對象的message方法的代碼,而是向receiver發送一條message消息,這條消息可能由receiver來處理,也可能由轉發給其他對象來處理,也有可能假裝沒有接收到這條消息而沒有處理。其實[receiver message]被編譯器轉化為:
id objc_msgSend ( id self, SEL op, ... );
下面從兩個數據結構id和SEL來逐步分析和理解Runtime有哪些重要的數據結構。
SEL
SEL是函數objc_msgSend第二個參數的數據類型,表示方法選擇器,按下面路徑打開objc.h文件:
SEL Data Structure
查看到SEL數據結構如下:
typedef struct objc_selector *SEL;
其實它就是映射到方法的C字符串,你可以通過Objc編譯器命令@selector()或者Runtime系統的sel_registerName函數來獲取一個SEL類型的方法選擇器。
如果你知道selector對應的方法名是什麼,可以通過NSString* NSStringFromSelector(SEL aSelector)方法將SEL轉化為字符串,再用NSLog列印。
id
接下來看objc_msgSend第一個參數的數據類型id,id是通用類型指針,能夠表示任何對象。按下面路徑打開objc.h文件:
id Data Structure
查看到id數據結構如下:
/// Represents an instance of a class.struct objc_object { Class isa OBJC_ISA_AVAILABILITY;};/// A pointer to an instance of a class.typedef struct objc_object *id;
id其實就是一個指向objc_object結構體指針,它包含一個Class isa成員,根據isa指針就可以順藤摸瓜找到對象所屬的類。
注意:根據Apple的官方文檔Key-Value Observing Implementation Details提及,key-value observing是使用isa-swizzling的技術實現的,isa指針在運行時被修改,指向一個中間類而不是真正的類。所以,你不應該使用isa指針來確定類的關係,而是使用class方法來確定實例對象的類。
Class
isa指針的數據類型是Class,Class表示對象所屬的類,按下面路徑打開objc.h文件:
Class Data Structure
/// An opaque type that represents an Objective-C class.typedef struct objc_class *Class;
可以查看到Class其實就是一個objc_class結構體指針,但這個頭文件找不到它的定義,需要在runtime.h才能找到objc_class結構體的定義。
按下面路徑打開runtime.h文件:
objc_class Data Structure