RunTime
RunTime
簡稱執行時。就是系統在執行的時候的一些機制,其中最主要的是訊息機制
。
RunTime
的2個重要特種
- C++等語言,在編譯時就已經確定了,執行時就是找到記憶體的位置,然後執行程式碼;而在Objective-C中,方法的呼叫實際上是以一種叫“訊息轉發”的方式進行的,也就是告訴class/object,我要呼叫某個object/class的某個方法;但是!具體是否呼叫某個方法,如何呼叫,可以在執行時決定和修改。
- class/object/method…的本質都是struct,因此在執行時也可以進行修改。
Class
先來看下 Class 的定義:
/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;
複製程式碼
實際上Class就是 objc_class
objc_class
在<objc/runtime.h>中,可以找到一個叫objc_class
的struct。我們看一下這個struct的定義
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class _Nullable super_class OBJC2_UNAVAILABLE;
const char * _Nonnull name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
//ivar列表,是一個objc_ivar_list型別的指標 代表例項變數
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
// method列表,是一個objc_method_list二級指標
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
//儲存常用method,加快訊息轉發速度
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
//儲存實現的protocols
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
複製程式碼
平常我們定義了一個class之後,實際上它會被編譯成一個這樣的struct;我們定義的變數、方法等,都儲存在struct中。
objc_object
/// Represents an instance of a class.
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
複製程式碼
當我們建立了一個類的例項後,其實生成了一個這樣的struct。它裡面的的Class isa,可以在訊息轉發時尋找到對應的class
objc_method_list
看一下 objc_class
中的 objc_method_list
定義
struct objc_method_list {
int method_count;
/* variable length structure */
struct objc_method method_list[1];
}
複製程式碼
objc_method_list
裡面儲存了一個 objc_method
objc_method
struct objc_method {
SEL method_name;
char *method_types;
IMP method_imp;
}
複製程式碼
這個objc_method就是我們熟悉的method。可以看到method主要由方法名、function指標組成,將SEL
和IMP
做了一個對映
SEL
typedef struct objc_selector *SEL;
複製程式碼
objc_selector
就是一個C字串。因此,SEL其實就是一個字串,可以理解成是對方法名的hash化
IMP
typedef void (*IMP)(void /* id, SEL, ... */ );
複製程式碼
IMP是方法的具體實現
當我們呼叫某個方法時,其實是向這個object傳送一個“訊息”,包含了方法名和引數。通過isa
找到objc_class
, 然後在objc_class
中遍歷尋找對應的objc_method
,找到之後再呼叫IMP。
也就是說,方法名SEl
和真正的實現程式碼IMP
之間,是由objc_method
來繫結的,這樣就實現了相對的動態化。
訊息傳遞具體流程
- 將方法呼叫轉化成
objc_msgSend
等方法,向object
傳送訊息; - 通過
objc_object
的isa
找到其所在class; - 檢測這個
SEL
是不是要忽略的;比如ARC中會忽略retain等操作; - 檢測target是否是nil;如果是的話,就忽略掉;
- 從cache中找
SEL
;一旦找到,就執行SEL
對應的IMP
; - 如果沒有,再到
methodLists
裡找; - 如果還沒有,再到
superclass
裡找,一直找到NSObject
; - 如果還沒有,進入動態方法解析。