平時編寫的OC代碼,底層都是由他實現的,如:git
[receiver message];
//底層運行時會被編譯器轉化爲:
objc_msgSend(receiver, selector)
//若是其還有參數好比:
[receiver message:(id)arg...];
//底層運行時會被編譯器轉化爲:
objc_msgSend(receiver, selector, arg1, arg2, ...)
複製代碼
先說幾個概念:
1)supercalss : 父類
2)subclass: 子類
3)isa : 概念很差說,官方文檔說的也不清晰。做用是根據 isa 指針就能夠找到對象所屬的類,可是isa指針在代碼運行時並不總指向實例對象所屬的類型,因此不能依靠它來肯定類型,要想肯定類型仍是須要用對象的 -class 方法。(PS:KVO 的實現機理就是將被觀察對象的isa指針指向一箇中間類而不是真實類型。)
4)class : 類,一個運行時類中關聯了它的父類指針、類名、成員變量、方法、緩存以及附屬的協議。(一個實例對象是一個類的實例)
5)meta class :元類,Objc 類自己也是一個對象 ,類對象所屬的類就叫作元類(一個類是元類的實例)
github
第一列是類的實例變量,如:[Person new]或者[[Person alloc] init]出來的對象;
第二列是類自己,存放父類指針、類名、成員變量、方法、緩存以及附屬的協議的信息;
第三列是元類
緩存
因此:數據結構
附舊版Class結構:app
typedef struct objc_class *Class;
Class 實際上是指向 objc_class 結構體的指針。objc_class 的數據結構以下:
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;
struct objc_cache *cache OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
複製代碼
/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;
/// A pointer to an instance of a class.
typedef struct objc_object *id;
複製代碼
Class是一個指向objc_class(類)結構體的指針,而id是一個指向objc_object(對象)結構體的指針。框架
objec_object(對象)中isa指針指向的類結構稱爲objec_class(該對象的類),其中存放着普通成員變量與對象方法 (「-」開頭的方法)。函數
objec_class(類)中isa指針指向的類結構稱爲metaclass(該類的元類),其中存放着static類型的成員變量與static類型的方法 (「+」開頭的方法)。spa
附圖:
舊版Class 3d
typedef struct objc_method *Method;
struct objc_method {
SEL method_name OBJC2_UNAVAILABLE; //方法名
char *method_types OBJC2_UNAVAILABLE; //方法類型
IMP method_imp OBJC2_UNAVAILABLE; //方法實現
}
複製代碼
objc_method 存儲了方法名,方法類型和方法實現。指針
方法類型 method_types 是個 char 指針,存儲方法的參數類型和返回值類型 method_imp 指向了方法的實現,本質是一個函數指針 Ivar Ivar 是表示成員變量的類型。
typedef struct objc_ivar *Ivar;
struct objc_ivar {
char *ivar_name OBJC2_UNAVAILABLE;
char *ivar_type OBJC2_UNAVAILABLE;
int ivar_offset OBJC2_UNAVAILABLE;
#ifdef __LP64__
int space OBJC2_UNAVAILABLE;
#endif
}
複製代碼
其中 ivar_offset 是基地址偏移字節
IMP在objc.h中的定義是:
typedef id (*IMP)(id, SEL, ...);
複製代碼
它就是一個函數指針,這是由編譯器生成的。當你發起一個 ObjC 消息以後,最終它會執行的那段代碼,就是由這個函數指針指定的,而 IMP 這個函數指針就指向了這個方法的實現。
問:oc是如何找到須要執行哪一個方法的?
答:當須要執行某個實例方法的時候(類方法相似),oc會先去該類的方法的緩存列表裏面查找,若找到了,則執行,不然,去該類的方法列表中查找是否存在該方法,存在,執行該方法並更新方法緩存列表,不然,去該父類緩存以及父類方法列表查找,直到根類,若還未找到,則啓用動態解析以及消息轉發流程,若仍是失敗,報unrecognized selector異常
郵箱: adrenine@163.com
郵箱: holaux@gmail.com
郵箱: ledahapple@icloud.com