原創(chuàng)文章轉(zhuǎn)載請(qǐng)注明出處,謝謝
很早就想講關(guān)于NSObject這個(gè)對(duì)象的模型,其實(shí)網(wǎng)上有不少講這方面知識(shí)的,但是我感覺很多都是千遍一律,而且有一些結(jié)論的并沒有系統(tǒng)的論證,所以我會(huì)從我的理解層面來解析主要分為兩方面,第一篇主要介紹NSObject整體的模型結(jié)構(gòu),第二篇是解析NSObject的一些類方法和實(shí)例方法。所以可能這兩篇分享會(huì)很長(zhǎng),這個(gè)也是為了詳細(xì)的介紹這些知識(shí)。
typedef struct objc_class *Class;
typedef struct objc_object *id;
@interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY;
}
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
NSObject實(shí)現(xiàn)了一個(gè)NSObject的protocol,里面包含一個(gè)isa的指針指向一個(gè)objc_class的結(jié)構(gòu)體;而id其實(shí)就是objc_object的結(jié)構(gòu)指針,所以它可以指向任何對(duì)象。
那么objc_class是一個(gè)什么結(jié)構(gòu)呢?
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;
這個(gè)結(jié)構(gòu)大家肯定不會(huì)陌生,這里重要的點(diǎn)主要包括兩方面的問題:
- isa和super_class指向的對(duì)象區(qū)別,也就是class和metaclass的區(qū)別(這個(gè)后面要重點(diǎn)詳細(xì)講)
- objc_ivar_list, objc_method_list, objc_cache, objc_protocol_list幾個(gè)struct的具體的結(jié)構(gòu)問題
接下來就是我們的正題了,到底一個(gè)NSObject對(duì)象編譯后變成什么樣了呢?
首先我們定義如下的兩個(gè)Class:
// AClass.h
@protocol AClassProtocol <NSObject>
- (void)protocolsMethod_AClass;
@end
@interface AClass : NSObject<AClassProtocol>
@property (nonatomic) NSString *name_AClass;
- (void)instanceMethods_AClass;
+ (void)classMethods_AClass;
@end
// AClass.m
@interface AClass() {
NSString *_address;
}
@end
@implementation AClass
- (void)instanceMethods_AClass {
}
- (void)protocolsMethod_AClass {
}
+ (void)classMethods_AClass {
}
@end
// BClass.h
@interface BClass : AClass
@property (nonatomic) NSString *name_BClass;
- (void)instanceMethods_BClass;
+ (void)classMethods_BClass;
@end
// BClass.m
@implementation BClass
- (void)instanceMethods_BClass {
}
+ (void)classMethods_BClass {
}
@end
接下來我們把它們編譯成C++文件,我們以AClass.cpp為例,來分析一下文件的組成結(jié)構(gòu):
struct _class_ro_t {
unsigned int flags;
unsigned int instanceStart;
unsigned int instanceSize;
unsigned int reserved;
const unsigned char *ivarLayout;
const char *name;
const struct _method_list_t *baseMethods;
const struct _objc_protocol_list *baseProtocols;
const struct _ivar_list_t *ivars;
const unsigned char *weakIvarLayout;
const struct _prop_list_t *properties;
};
struct _class_t {
struct _class_t *isa;
struct _class_t *superclass;
void *cache;
void *vtable;
struct _class_ro_t *ro;
};
編譯以后的結(jié)構(gòu)和我們之前定義的objc_class稍微有點(diǎn)區(qū)別,但是大致的結(jié)構(gòu)還是一樣的,_class_ro_t中定義了我們之前所說的幾個(gè)struct結(jié)構(gòu)。
static struct _class_ro_t _OBJC_CLASS_RO_$_AClass __attribute__ ((used, section ("__DATA,__objc_const"))) = {
0, __OFFSETOFIVAR__(struct AClass, _name), sizeof(struct AClass_IMPL),
(unsigned int)0,
0,
"AClass",
(const struct _method_list_t *)&_OBJC_$_INSTANCE_METHODS_AClass,
(const struct _objc_protocol_list *)&_OBJC_CLASS_PROTOCOLS_$_AClass,
(const struct _ivar_list_t *)&_OBJC_$_INSTANCE_VARIABLES_AClass,
0,
(const struct _prop_list_t *)&_OBJC_$_PROP_LIST_AClass,
};
extern "C" __declspec(dllexport) struct _class_t OBJC_CLASS_$_AClass __attribute__ ((used, section ("__DATA,__objc_data"))) = {
0, // &OBJC_METACLASS_$_AClass,
0, // &OBJC_CLASS_$_NSObject,
0, // (void *)&_objc_empty_cache,
0, // unused, was (void *)&_objc_empty_vtable,
&_OBJC_CLASS_RO_$_AClass,
};
我們的AClass被定義成一個(gè)叫做OBJC_CLASS_$AClass的struct對(duì)象,這里的metaclass和class等等目前都是0,先不要急后面會(huì)初始化的,這里重點(diǎn)先介紹OBJC_CLASS_RO$AClass的結(jié)構(gòu),它就是一個(gè)_class_ro_t的結(jié)構(gòu)體,我們發(fā)現(xiàn)_method_list_t,_objc_protocol_list,_ivar_list_t,_prop_list_t分別在里面被初始化了值,那么我們就來看一下它們對(duì)應(yīng)的結(jié)構(gòu):
// _OBJC_$_INSTANCE_METHODS_AClass
struct _objc_method {
struct objc_selector * _cmd;
const char *method_type;
void *_imp;
};
static struct /*_method_list_t*/ {
unsigned int entsize; // sizeof(struct _objc_method)
unsigned int method_count;
struct _objc_method method_list[4];
} _OBJC_$_INSTANCE_METHODS_AClass __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_objc_method),
4,
{
{(struct objc_selector *)"instanceMethods_AClass", "v16@0:8", (void *)_I_AClass_instanceMethods_AClass},
{(struct objc_selector *)"protocolsMethod_AClass", "v16@0:8", (void *)_I_AClass_protocolsMethod_AClass},
{(struct objc_selector *)"name", "@16@0:8", (void *)_I_AClass_name},
{(struct objc_selector *)"setName:", "v24@0:8@16", (void *)_I_AClass_setName_}
}
};
_OBJC_$__INSTANCE_METHODS_AClass是一個(gè)實(shí)例方法的列表,其中也包括了get/set方法,以及聲明了protocol的方法。而_objc_method的結(jié)構(gòu)其實(shí)就是一個(gè)objc_selector,加上類型type,還有就是一個(gè)imp的指針。(有沒有發(fā)現(xiàn)少了一個(gè)類方法在里面,下面會(huì)介紹原因)
// _OBJC_CLASS_PROTOCOLS_$_AClass
static struct /*_protocol_list_t*/ {
long protocol_count; // Note, this is 32/64 bit
struct _protocol_t *super_protocols[1];
} _OBJC_CLASS_PROTOCOLS_$_AClass __attribute__ ((used, section ("__DATA,__objc_const"))) = {
1,
&_OBJC_PROTOCOL_AClassProtocol
};
static struct /*_method_list_t*/ {
unsigned int entsize; // sizeof(struct _objc_method)
unsigned int method_count;
struct _objc_method method_list[1];
} _OBJC_PROTOCOL_INSTANCE_METHODS_AClassProtocol __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_objc_method),
1,
{{(struct objc_selector *)"protocolsMethod_AClass", "v16@0:8", 0}}
};
struct _protocol_t _OBJC_PROTOCOL_AClassProtocol __attribute__ ((used, section ("__DATA,__datacoal_nt,coalesced"))) = {
0,
"AClassProtocol",
(const struct _protocol_list_t *)&_OBJC_PROTOCOL_REFS_AClassProtocol,
(const struct method_list_t *)&_OBJC_PROTOCOL_INSTANCE_METHODS_AClassProtocol,
0,
0,
0,
0,
sizeof(_protocol_t),
0,
(const char **)&_OBJC_PROTOCOL_METHOD_TYPES_AClassProtocol
};
static struct /*_protocol_list_t*/ {
long protocol_count; // Note, this is 32/64 bit
struct _protocol_t *super_protocols[1];
} _OBJC_PROTOCOL_REFS_AClassProtocol __attribute__ ((used, section ("__DATA,__objc_const"))) = {
1,
&_OBJC_PROTOCOL_NSObject
};
_OBJC_CLASS_PROTOCOLS_$AClass是一個(gè)比較復(fù)雜的結(jié)構(gòu)體,因?yàn)槠南拗粕厦娴拇a我并沒有給全,所有protocol的方法都會(huì)被添加到這個(gè)list里,但是其中還會(huì)包含NSObject protocol的那些方法,也就是_OBJC_PROTOCOL_NSObject中我沒有給出來的那部分,因?yàn)楸容^復(fù)雜,所以我們以后分開單獨(dú)講。
// _OBJC_$_INSTANCE_VARIABLES_AClass
struct _ivar_t {
unsigned long int *offset; // pointer to ivar offset location
const char *name;
const char *type;
unsigned int alignment;
unsigned int size;
};
static struct /*_ivar_list_t*/ {
unsigned int entsize; // sizeof(struct _prop_t)
unsigned int count;
struct _ivar_t ivar_list[2];
} _OBJC_$_INSTANCE_VARIABLES_AClass __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_ivar_t),
2,
{
{(unsigned long int *)&OBJC_IVAR_$_AClass$_address, "_address", "@\"NSString\"", 3, 8},
{(unsigned long int *)&OBJC_IVAR_$_AClass$_name_AClass, "_name_AClass", "@\"NSString\"", 3, 8}
}
};
_OBJC_$INSTANCE_VARIABLES_AClass是一個(gè)指向?qū)嵗兞康牧斜?,這里我們會(huì)發(fā)現(xiàn)定義成屬性的name也會(huì)變成一個(gè)實(shí)例變量,其實(shí)是因?yàn)榫幾g器為你自動(dòng)加上了@synthesize,所以變成了_name的一個(gè)實(shí)例變量,_ivar_t定義也是非常的簡(jiǎn)單,包括了name,偏移量,type,size等等。
// _OBJC_$_PROP_LIST_AClass
struct _prop_t {
const char *name;
const char *attributes;
};
static struct /*_prop_list_t*/ {
unsigned int entsize; // sizeof(struct _prop_t)
unsigned int count_of_properties;
struct _prop_t prop_list[1];
} _OBJC_$_PROP_LIST_AClass __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_prop_t),
1,
{{"name_AClass","T@\"NSString\",N,V_name_AClass"}}
};
_OBJC_$PROP_LIST_AClass很明顯就是屬性的列表,即聲明了@property的變量。
最后就是關(guān)于objc_cache的一些介紹,其實(shí)我們每次objc_msgsend一個(gè)方法的時(shí)候都是去遍歷_method_list_t的,這樣對(duì)于一些常用的方法就會(huì)導(dǎo)致效率不高,這個(gè)時(shí)候我們就會(huì)把常用的一些方法cache下來,通過key-value的map方式,將name對(duì)應(yīng)到各自的imp,這樣就大大提高了效率。
好,講到這里,我們已經(jīng)解決了我們的其中一個(gè)問題,接下來就是要講最重要的問題了,OC中的metaclass到底是個(gè)什么東西,了解過的同學(xué)應(yīng)該都知道,isa指針指向的其實(shí)就是一個(gè)metaclass,metaclass其實(shí)是一個(gè)類對(duì)象的類,可能這樣解釋會(huì)很抽象,確實(shí)不容易理解,我們通過實(shí)際的代碼結(jié)構(gòu)來驗(yàn)證這個(gè)問題。
// AClass.cpp
static void OBJC_CLASS_SETUP_$_AClass(void ) {
OBJC_METACLASS_$_AClass.isa = &OBJC_METACLASS_$_NSObject;
OBJC_METACLASS_$_AClass.superclass = &OBJC_METACLASS_$_NSObject;
OBJC_METACLASS_$_AClass.cache = &_objc_empty_cache;
OBJC_CLASS_$_AClass.isa = &OBJC_METACLASS_$_AClass;
OBJC_CLASS_$_AClass.superclass = &OBJC_CLASS_$_NSObject;
OBJC_CLASS_$_AClass.cache = &_objc_empty_cache;
}
以上就是我們之前在前面編譯后的AClass對(duì)象,OBJC_CLASS_$AClass的isa指針是指向一個(gè)OBJC_METACLASS_$AClass,而superclass是指向OBJC_CLASS_$NSObject;那我們來看一下OBJC_METACLASS_$AClass的定義又是什么樣的呢?
extern "C" __declspec(dllexport) struct _class_t OBJC_METACLASS_$_AClass __attribute__ ((used, section ("__DATA,__objc_data"))) = {
0, // &OBJC_METACLASS_$_NSObject,
0, // &OBJC_METACLASS_$_NSObject,
0, // (void *)&_objc_empty_cache,
0, // unused, was (void *)&_objc_empty_vtable,
&_OBJC_METACLASS_RO_$_AClass,
};
static struct _class_ro_t _OBJC_METACLASS_RO_$_AClass __attribute__ ((used, section ("__DATA,__objc_const"))) = {
1, sizeof(struct _class_t), sizeof(struct _class_t),
(unsigned int)0,
0,
"AClass",
(const struct _method_list_t *)&_OBJC_$_CLASS_METHODS_AClass,
0,
0,
0,
0,
};
static struct /*_method_list_t*/ {
unsigned int entsize; // sizeof(struct _objc_method)
unsigned int method_count;
struct _objc_method method_list[1];
} _OBJC_$_CLASS_METHODS_AClass __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_objc_method),
1,
{{(struct objc_selector *)"classMethods_AClass", "v16@0:8", (void *)_C_AClass_classMethods_AClass}}
};
看了上面的定義我們發(fā)現(xiàn),之前我們沒有在前面的_method_list中找到的那個(gè)類方法原來出現(xiàn)在這里,也就說OBJC_METACLASS$AClass里其實(shí)包含了類方法。這個(gè)就驗(yàn)證了網(wǎng)上說的一個(gè)結(jié)論:
- 當(dāng)你向一個(gè)對(duì)象發(fā)送消息時(shí),runtime會(huì)在這個(gè)對(duì)象所屬的那個(gè)類的方法列表中查找。
- 當(dāng)你向一個(gè)類發(fā)送消息時(shí),runtime會(huì)在這個(gè)類的meta-class的方法列表中查找。
OBJC_METACLASS$AClass的isa又是指向OBJC_METACLASS_$NSObject,superclass也是指向OBJC_METACLASS_$NSObject。好,我們接下來把BClass中的isa和superclass也聯(lián)系起來:
extern "C" __declspec(dllexport) struct _class_t OBJC_CLASS_$_BClass __attribute__ ((used, section ("__DATA,__objc_data"))) = {
0, // &OBJC_METACLASS_$_BClass,
0, // &OBJC_CLASS_$_AClass,
0, // (void *)&_objc_empty_cache,
0, // unused, was (void *)&_objc_empty_vtable,
&_OBJC_CLASS_RO_$_BClass,
};
static void OBJC_CLASS_SETUP_$_BClass(void ) {
OBJC_METACLASS_$_BClass.isa = &OBJC_METACLASS_$_NSObject;
OBJC_METACLASS_$_BClass.superclass = &OBJC_METACLASS_$_AClass;
OBJC_METACLASS_$_BClass.cache = &_objc_empty_cache;
OBJC_CLASS_$_BClass.isa = &OBJC_METACLASS_$_BClass;
OBJC_CLASS_$_BClass.superclass = &OBJC_CLASS_$_AClass;
OBJC_CLASS_$_BClass.cache = &_objc_empty_cache;
}
我們把這些信息串聯(lián)在一起,可以得出如下的一張分析圖:

是不是發(fā)現(xiàn)這個(gè)圖在哪里好像見到過,沒錯(cuò)就是介紹metaclass原理的一張圖:

但是仔細(xì)比較還是會(huì)發(fā)現(xiàn),有一些不同的地方,就是關(guān)于NSObject的superclass到底是什么,以及Meta_NSObject的isa和superclass是什么,因?yàn)閺奈覀冎暗膶?shí)驗(yàn)?zāi)P褪菬o法得出的,我試圖編譯NSObject.mm的源碼,但是由于環(huán)境的問題失敗了,所以我們需要通過其他的手段來驗(yàn)證圖上的解釋是否是正確的,我們通過在runtime的時(shí)候動(dòng)態(tài)生成一個(gè)class,它繼承自BClass,如下:
Class newClass =
objc_allocateClassPair([BClass class], "BClassSubClass", 0);
class_addMethod(newClass, @selector(report), (IMP)ReportFunction, "v@:");
objc_registerClassPair(newClass);
id instanceOfNewClass=[[newClass alloc] init];
[instanceOfNewClass performSelector:@selector(report)];
void ReportFunction(id self, SEL _cmd) {
Class superClazz = [self superclass];
while (superClazz) {
NSLog(@"superclass %p %@", superClazz, superClazz);
superClazz = [superClazz superclass];
}
NSLog(@"%p %@", superClazz, superClazz);
Class metaClass = object_getClass([self class]);
while (metaClass) {
NSLog(@"%p is metaClass : %d", metaClass, class_isMetaClass(metaClass));
if (metaClass != object_getClass(metaClass)) {
metaClass = object_getClass(metaClass);
} else {
break;
}
}
NSLog(@"BClass's class is %p", [BClass class]);
NSLog(@"BClass's meta class is %p", object_getClass([BClass class]));
NSLog(@"AClass's class is %p", [AClass class]);
NSLog(@"AClass's meta class is %p", object_getClass([AClass class]));
NSLog(@"NSObject's class is %p", [NSObject class]);
NSLog(@"NSObject's superclass is %p", [[NSObject class] superclass]);
NSLog(@"NSObject's meta class is %p", object_getClass([NSObject class]));
NSLog(@"NSObject's meta superclass is %p", [object_getClass([NSObject class]) superclass]);
}
// out put
2016-06-23 00:03:39.079 InitDemo[1775:97046] superclass 0x100002908 BClass
2016-06-23 00:03:39.079 InitDemo[1775:97046] superclass 0x1000028e0 AClass
2016-06-23 00:03:39.080 InitDemo[1775:97046] superclass 0x7fff79ea20f0 NSObject
2016-06-23 00:03:39.080 InitDemo[1775:97046] 0x0 (null)
2016-06-23 00:03:39.080 InitDemo[1775:97046] 0x100508dc0 is metaClass : 1
2016-06-23 00:03:39.080 InitDemo[1775:97046] 0x7fff79ea2118 is metaClass : 1
2016-06-23 00:03:39.080 InitDemo[1775:97046] BClass's class is 0x100002908
2016-06-23 00:03:39.080 InitDemo[1775:97046] BClass's meta class is 0x100002930
2016-06-23 00:03:39.080 InitDemo[1775:97046] AClass's class is 0x1000028e0
2016-06-23 00:03:39.080 InitDemo[1775:97046] AClass's meta class is 0x1000028b8
2016-06-23 00:03:39.080 InitDemo[1775:97046] NSObject's class is 0x7fff79ea20f0
2016-06-23 00:03:39.081 InitDemo[1775:97046] NSObject's superclass is 0x0
2016-06-23 00:03:39.081 InitDemo[1775:97046] NSObject's meta class is 0x7fff79ea2118
2016-06-23 00:03:39.081 InitDemo[1775:97046] NSObject's meta superclass is 0x7fff79ea20f0
首先告訴大家的是object_getClass函數(shù)其實(shí)是去獲取class的isa指針;好,我們發(fā)現(xiàn) NSObject's superclass is 0x0,確實(shí)和圖上顯示一樣,NSObject的superclass是指向nil的,而且NSObject's meta superclass的地址是和NSObject's class相同,代表meta_NSObject的superclass是指向NSObject的;而meta_NSObject的metaclass的地址和meta_NSObject的地址都是0x7fff79ea2118,所以meta_NSObject的metaclass是指向自己的。這樣我們就可以把我們自己的圖補(bǔ)充完整。

所以最后我們可以得出來的結(jié)論就是:
- 每個(gè)Class都有一個(gè)isa指針指向一個(gè)唯一的Meta Class
- 每一個(gè)Meta Class的isa指針都指向最上層的Meta Class(圖中的NSObject的Meta Class)
- 最上層的Meta Class的isa指針指向自己,形成一個(gè)回路
- 每一個(gè)Meta Class的super class指針指向它原本Class的 Super Class的Meta Class, 但是最上層的Meta Class的 Super Class指向NSObject Class本身.
- 最上層的NSObject Class的super class指向 nil
好了,到現(xiàn)在我們所要說明的兩方面問題都已經(jīng)解釋了,關(guān)于NSObject的一些方法,我會(huì)在后面在來分析。
最后提一點(diǎn)就是關(guān)于self和[self class]的區(qū)別,self 是指向于一個(gè)objc_object結(jié)構(gòu)體的首地址, 返回的是objc_class結(jié)構(gòu)體的首地址,也就是self->isa的值。