此文實(shí)際成于 2015/07/29
Objc explain Classes and metaclasses
Objective-C 是基于類的對(duì)象系統(tǒng)。
每一個(gè)對(duì)象都是某一個(gè)類的一個(gè)實(shí)例。
對(duì)象的
isa指針指向它的類。類描述對(duì)象的數(shù)據(jù)信息如:分配的內(nèi)存大小,
ivar類型及布局。類同時(shí)描述了對(duì)象的行為如:它所響應(yīng)的選擇器;它所實(shí)現(xiàn)的實(shí)例方法。
類的方法列表是實(shí)例方法的集合,對(duì)象能夠響應(yīng)選擇器。
當(dāng)發(fā)送一個(gè)消息給對(duì)象時(shí),objc_msgSend()查詢類(或超類,如果有的話)的方法列表,來決定調(diào)用哪一個(gè)方法。每一個(gè) Objective-C 類同樣是一個(gè)對(duì)象。 它有一個(gè)
isa指針及其他數(shù)據(jù),
同樣能響應(yīng)選擇器。當(dāng)你像這樣[NSObject alloc]調(diào)用一個(gè)類方法(class method)時(shí)。實(shí)際是你是在發(fā)送消息給哪一個(gè)類對(duì)象。因?yàn)橐粋€(gè)類也是一個(gè)對(duì)象,它就必須是某一個(gè)元類(meta class)的實(shí)例.
metaclass 是類對(duì)象的描述。正如類是普通的實(shí)例的描述。
實(shí)際上,
- 類的方法列表就是類方法列表,類對(duì)象響應(yīng)的選擇器。
- 當(dāng)你發(fā)送一個(gè)消息給一個(gè)類(一個(gè)元類的實(shí)例),
objc_msgSend()查找元類(或其超類,如果有的話)的方法列表來決定調(diào)用哪一個(gè)方法。
正如實(shí)例方法以類來描述以代表類對(duì)象。類方法以元類來描述來代表實(shí)例對(duì)象。
什么是元類?
元類是根類的元類的實(shí)例。 根元類本身是根根元類的一個(gè)實(shí)例。isa鏈在這里以一個(gè)循環(huán)結(jié)尾: 實(shí)例到類對(duì)元類到根類到它自身。元類的 isa指針的行為一般不影響什么的。因?yàn)樵诂F(xiàn)實(shí)中沒有人發(fā)送信息給元類對(duì)象。
最重要的是一個(gè)元類的超類。元類的超類鏈跟類的越類鏈?zhǔn)遣⑿械?,所以類方法的繼承也跟實(shí)例方法的繼承是并行的。并且根元類的越類是根類,因此每一個(gè)類對(duì)象響應(yīng)根類的實(shí)例方法。
最后,類對(duì)象是根類的或其子類的實(shí)例,正如其他對(duì)象一個(gè)。
如下圖:

對(duì)應(yīng)代碼如下:
// Connect to superclasses and metaclasses
cls->initClassIsa(meta);
if (superclass) {
meta->initClassIsa(superclass->ISA()->ISA());
cls->superclass = superclass;
meta->superclass = superclass->ISA();
addSubclass(superclass, cls);
addSubclass(superclass->ISA(), meta);
} else {
meta->initClassIsa(meta);
cls->superclass = Nil;
meta->superclass = cls;
addSubclass(cls, meta);
}
上面的 對(duì)于isa的設(shè)置主要在 cls->initClassIsa(meta) 方法中體現(xiàn) 。
inline void
objc_object::initClassIsa(Class cls)
{
initIsa(cls);
}
然后很多與初始化isa操作,最后都調(diào)用到了initIsa(cls) 方法上來。
對(duì)于非 Tagged Pointer 的 ISA 類型,
其初始 化操作就是一個(gè)簡單的賦值操作:
inline void
objc_object::initIsa(Class cls)
{
assert(!isTaggedPointer());
isa = (uintptr_t)cls;
}
對(duì)于 Tagged Pointer 實(shí)現(xiàn)的
其實(shí)現(xiàn)稍微復(fù)雜一些,如下 :
inline void
objc_object::initIsa(Class cls)
{
initIsa(cls, false, false);
}
inline void
objc_object::initClassIsa(Class cls)
{
if (DisableIndexedIsa) {
initIsa(cls, false, false);
} else {
initIsa(cls, true, false);
}
}
inline void
objc_object::initProtocolIsa(Class cls)
{
return initClassIsa(cls);
}
inline void
objc_object::initInstanceIsa(Class cls, bool hasCxxDtor)
{
assert(!UseGC);
assert(!cls->requiresRawIsa());
assert(hasCxxDtor == cls->hasCxxDtor());
initIsa(cls, true, hasCxxDtor);
}
inline void
objc_object::initIsa(Class cls, bool indexed, bool hasCxxDtor)
{
assert(!isTaggedPointer());
if (!indexed) {
isa.cls = cls;
} else {
assert(!DisableIndexedIsa);
isa.bits = ISA_MAGIC_VALUE;
// isa.magic is part of ISA_MAGIC_VALUE
// isa.indexed is part of ISA_MAGIC_VALUE
isa.has_cxx_dtor = hasCxxDtor;
isa.shiftcls = (uintptr_t)cls >> 3;
}
}
小結(jié)
當(dāng)像一個(gè)對(duì)象發(fā)送消息時(shí),方法的查找以對(duì)象的isa指針開始,然后繼續(xù)到其超類鏈。
實(shí)例方法在類中定義
類方法在元類定義加上根類(非元類)。
類方法與實(shí)例方法的查找
按上面的說法,類方法其實(shí)是類對(duì)象isa所指向的元類的實(shí)例方法。
因此其實(shí)現(xiàn)如下 :
/***********************************************************************
* class_getClassMethod. Return the class method for the specified
* class and selector.
**********************************************************************/
Method class_getClassMethod(Class cls, SEL sel)
{
if (!cls || !sel) return nil;
return class_getInstanceMethod(cls->getMeta(), sel);
}
新類的內(nèi)存分配
/***********************************************************************
* objc_allocateClassPair
* fixme
* Locking: acquires runtimeLock
**********************************************************************/
Class objc_allocateClassPair(Class superclass, const char *name,
size_t extraBytes)
{
Class cls, meta;
rwlock_write(&runtimeLock);
// Fail if the class name is in use.
// Fail if the superclass isn't kosher.
if (getClass(name) || !verifySuperclass(superclass, true/*rootOK*/)) {
rwlock_unlock_write(&runtimeLock);
return nil;
}
// Allocate new classes.
cls = alloc_class_for_subclass(superclass, extraBytes);
meta = alloc_class_for_subclass(superclass, extraBytes);
// fixme mangle the name if it looks swift-y?
objc_initializeClassPair_internal(superclass, name, cls, meta);
rwlock_unlock_write(&runtimeLock);
return cls;
}
從
cls = alloc_class_for_subclass(superclass, extraBytes);
meta = alloc_class_for_subclass(superclass, extraBytes);
可以看出,類和元類的繼承是并行的。
整個(gè)類復(fù)雜的關(guān)聯(lián)就在下面這大段代碼中體現(xiàn):
/***********************************************************************
* objc_initializeClassPair
* Locking: runtimeLock must be write-locked by the caller
**********************************************************************/
// &UnsetLayout is the default ivar layout during class construction
static const uint8_t UnsetLayout = 0;
static void objc_initializeClassPair_internal(Class superclass, const char *name, Class cls, Class meta)
{
rwlock_assert_writing(&runtimeLock);
class_ro_t *cls_ro_w, *meta_ro_w;
cls->cache.setEmpty();
meta->cache.setEmpty();
cls->setData((class_rw_t *)_calloc_internal(sizeof(class_rw_t), 1));
meta->setData((class_rw_t *)_calloc_internal(sizeof(class_rw_t), 1));
cls_ro_w = (class_ro_t *)_calloc_internal(sizeof(class_ro_t), 1);
meta_ro_w = (class_ro_t *)_calloc_internal(sizeof(class_ro_t), 1);
cls->data()->ro = cls_ro_w;
meta->data()->ro = meta_ro_w;
// Set basic info
cls->data()->flags = RW_CONSTRUCTING | RW_COPIED_RO | RW_REALIZED | RW_REALIZING;
meta->data()->flags = RW_CONSTRUCTING | RW_COPIED_RO | RW_REALIZED | RW_REALIZING;
cls->data()->version = 0;
meta->data()->version = 7;
cls_ro_w->flags = 0;
meta_ro_w->flags = RO_META;
if (!superclass) {
cls_ro_w->flags |= RO_ROOT;
meta_ro_w->flags |= RO_ROOT;
}
if (superclass) {
cls_ro_w->instanceStart = superclass->unalignedInstanceSize();
meta_ro_w->instanceStart = superclass->ISA()->unalignedInstanceSize();
cls->setInstanceSize(cls_ro_w->instanceStart);
meta->setInstanceSize(meta_ro_w->instanceStart);
} else {
cls_ro_w->instanceStart = 0;
meta_ro_w->instanceStart = (uint32_t)sizeof(objc_class);
cls->setInstanceSize((uint32_t)sizeof(id)); // just an isa
meta->setInstanceSize(meta_ro_w->instanceStart);
}
cls_ro_w->name = _strdup_internal(name);
meta_ro_w->name = _strdup_internal(name);
cls_ro_w->ivarLayout = &UnsetLayout;
cls_ro_w->weakIvarLayout = &UnsetLayout;
// Connect to superclasses and metaclasses
cls->initClassIsa(meta);
if (superclass) {
meta->initClassIsa(superclass->ISA()->ISA());
cls->superclass = superclass;
meta->superclass = superclass->ISA();
addSubclass(superclass, cls);
addSubclass(superclass->ISA(), meta);
} else {
meta->initClassIsa(meta);
cls->superclass = Nil;
meta->superclass = cls;
addSubclass(cls, meta);
}
}
Objective-C 的類是以 struct objc_class來實(shí)現(xiàn)的。
而其繼承自 struct objc_object 即 id
struct objc_class有新舊兩種定義。老的定義雖然很 OS X 10.5 就不再用了。但是有助于幫助我們理解 struct objc_class有什么 。
類的老的運(yùn)行時(shí)定義
老的定義在 objc-runtime-old.h中。
struct objc_class : objc_object {
Class superclass;
const char *name;
uint32_t version;
uint32_t info;
uint32_t instance_size;
struct old_ivar_list *ivars;
struct old_method_list **methodLists;
Cache cache;
struct old_protocol_list *protocols;
// CLS_EXT only
const uint8_t *ivar_layout;
struct old_class_ext *ext;
上面的 Class類型,是:
typedef struct objc_class *Class
它們都在 objc-private.h中有定義:
struct objc_class;
struct objc_object;
typedef struct objc_class *Class;
typedef struct objc_object *id;
也就是說objc_class實(shí)現(xiàn)了一種單鏈表的結(jié)構(gòu)。也可以說它是類的單繼承結(jié)構(gòu)。
Class好比是鏈表結(jié)構(gòu)中的一個(gè)Node
從上面的結(jié)構(gòu)定義可以看出老式的類定義有哪些內(nèi)容呢?
- `Class superclass` 其指向的超類
- `const char *name` 類名
- `version` 類的版本
- `info` 類信息
- `instance_size` 類對(duì)象實(shí)例的大小
- `struct objc_ivar_list *ivars` 實(shí)例變量列表
- `struct objc_method_list **methodLists` 實(shí)例方法列表
- `struct objc_cache *cache` 方法解析緩存的Hash 表
- `struct objc_protocol_list *protocols` 類實(shí)例實(shí)現(xiàn)的協(xié)議列表
也不能忘了其公開的頭文件的聲明 `runtime.h`
中將`isa`字段也包括在內(nèi)。但是實(shí)現(xiàn)是在`struct objc_object`中聲明的。
```c
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
}
```
`isa` 表明一個(gè)實(shí)際的對(duì)象實(shí)際上是一個(gè)什么類。實(shí)際上每一個(gè) objc 的對(duì)象都 是一個(gè)一個(gè)`isa`指針開始的,要不 objc 運(yùn)行時(shí)不知道怎么處理這一塊內(nèi)存,這一個(gè)對(duì)象。
新的類定義
其基本聲明如下 :
struct objc_class : objc_object {
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
class_rw_t *data() {
return bits.data();
}
}
新的實(shí)現(xiàn)更復(fù)雜高效。
上面介紹的實(shí)例變量列表,方法列表,協(xié)議列表都由 class_rw_t結(jié)構(gòu)來實(shí)現(xiàn)了。
其聲明如下 :
struct class_rw_t {
uint32_t flags;
uint32_t version;
const class_ro_t *ro;
union {
method_list_t **method_lists; // RW_METHOD_ARRAY == 1
method_list_t *method_list; // RW_METHOD_ARRAY == 0
};
struct chained_property_list *properties;
const protocol_list_t ** protocols;
Class firstSubclass;
Class nextSiblingClass;
char *demangledName;
其中 const class_ro_t *ro; 存儲(chǔ)了方法列表,協(xié)議列表,實(shí)例變量列表的關(guān)鍵信息。
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;
#ifdef __LP64__
uint32_t reserved;
#endif
const uint8_t * ivarLayout;
const char * name;
const method_list_t * baseMethods;
const protocol_list_t * baseProtocols;
const ivar_list_t * ivars;
const uint8_t * weakIvarLayout;
const property_list_t *baseProperties;
};