元類(meta class)茬腿,這個(gè)名字想必很多人都聽過聚至,網(wǎng)上也有很多關(guān)于元類的介紹慧瘤,今天我就按照自己這兩天的理解來簡單探討一下這個(gè)玩意戴已,有誤之處還望指出固该。
首先,下載objc源碼糖儡,源碼地址:https://opensource.apple.com/tarballs/objc4/
打開鏈接后會發(fā)現(xiàn)有很多版本伐坏,我直接下載的最新版(709版本)
認(rèn)識NSObject
1.打開objc工程的NSObject.h,找到NSObject類的定義
@interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY; //發(fā)現(xiàn)NSObject包含一個(gè)Class對象
}
2.繼續(xù)查看Class類型
typedef struct objc_class *Class;
3.繼續(xù)查看objc_class類型
struct objc_class : objc_object { //objc_class繼承自objc_object
Class superclass;
const char *name;
uint32_t version;
uint32_t info;
...
}
4.查看objc_object類型
struct objc_object {
private:
isa_t isa; //這個(gè)東西好像很牛逼握联,繼續(xù)看一下
...
}
5.查看isa_t類型
union isa_t
{
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
Class cls; //誒桦沉,這個(gè)東西又出現(xiàn)了
uintptr_t bits;
}
簡單用圖片表示一下:
圖-1
那么簡單總結(jié)一下就是,NSObject包含一個(gè)Class金闽,Class中包含一個(gè)superclass和cls
meta class 獲取
1.打開objc工程的runtime.h纯露,找到meta class的獲取接口
Class objc_getMetaClass(const char *name) {
//下面代碼進(jìn)行了簡化
//1.通過類名找到類對象(注意不是類實(shí)例對象)
Class cls = objc_getClass (aClassName);
//2.返回上面圖-1中最里面的cls
return cls->isa.cls;
}
2.meta class的獲取其實(shí)就是獲取類對象包含的cls,而我們在實(shí)際開發(fā)中是不能調(diào)用到cls的代芜,這時(shí)埠褪,可以通過object_getClass來實(shí)現(xiàn)。
查看object_getClass的實(shí)現(xiàn)
Class object_getClass(id obj) {
//下面代碼經(jīng)過簡化
return obj->isa.cls; //也是返回cls
}
通過測試代碼來分析源碼
//引入rumtime頭文件
#import <objc/objc-runtime.h>
//定義一個(gè)簡單的類
@interface Father : NSObject
@property (nonatomic, strong) NSString *name;
@end
//各種實(shí)例打印
Father* f = [[Father alloc] init];
NSLog(@"f address:%p", f);
NSLog(@"[f class] address:%p", [f class]);
NSLog(@"[Father class] address:%p", [Father class]);
NSLog(@"objc_getMetaClass address:%p", objc_getMetaClass("Father"));
NSLog(@"objc_getClass address:%p", object_getClass([Father class]));
打印結(jié)果:
打印結(jié)果:
2017-04-26 11:46:37.104 runtimeDemo[190:22480332] f address:0x600000011e70
2017-04-26 11:46:37.104 runtimeDemo[190:22480332] [f class] address:0x1063d5ff0
2017-04-26 11:46:37.105 runtimeDemo[190:22480332] [Father class] address:0x1063d5ff0
2017-04-26 11:46:37.105 runtimeDemo[190:22480332] objc_getMetaClass address:0x1063d5fc8
2017-04-26 11:46:37.105 runtimeDemo[190:22480332] objc_getClass address:0x1063d5fc8
通過結(jié)果進(jìn)行分析:
- 類實(shí)例對象本身不是元類
- 類實(shí)例對象通過class方法獲取到的對象為類對象挤庇,[f class] == [Father class]
- 通過類對象調(diào)用的object_getClass得到的是meta class
meta class 繼承
meta class繼承圖
這是一張很牛逼的圖钞速,我們用盡量簡單的代碼來測試一下:
Son *s = [[Son alloc] init]; //Instance of Subclass
Class cls = [s class]; //Subclass class
Class meta = object_getClass(cls); //Subclass meta
Class superclass = [cls superclass];
Class supermeta = [meta superclass];
Class supermeta2 = object_getClass(superclass);
Class rootclass = [superclass superclass];
Class rootmeta = [supermeta superclass];
Class rootmeta2 = object_getClass(rootclass);
Class nilclass = [rootclass superclass];
Class superrootmeta = [rootmeta superclass];
NSLog(@"s address:%p", s);
NSLog(@"cls address:%p", cls);
NSLog(@"meta address:%p", meta);
NSLog(@"superclass address:%p", superclass);
NSLog(@"supermeta address:%p", supermeta);
NSLog(@"supermeta2 address:%p", supermeta2);
NSLog(@"rootclass address:%p", rootclass);
NSLog(@"rootmeta address:%p", rootmeta);
NSLog(@"rootmeta2 address:%p", rootmeta2);
NSLog(@"nilclass address:%p", nilclass);
NSLog(@"superrootmeta address:%p", superrootmeta);
打印結(jié)果
2017-04-26 12:32:10.412 runtimeDemo[1194:22584480] s address:0x608000015700
2017-04-26 12:32:10.412 runtimeDemo[1194:22584480] cls address:0x10540f060
2017-04-26 12:32:10.412 runtimeDemo[1194:22584480] meta address:0x10540f038
2017-04-26 12:32:10.412 runtimeDemo[1194:22584480] superclass address:0x10540f0b0
2017-04-26 12:32:10.413 runtimeDemo[1194:22584480] supermeta address:0x10540f088
2017-04-26 12:32:10.413 runtimeDemo[1194:22584480] supermeta2 address:0x10540f088
2017-04-26 12:32:10.413 runtimeDemo[1194:22584480] rootclass address:0x105da8e88
2017-04-26 12:32:10.413 runtimeDemo[1194:22584480] rootmeta address:0x105da8e38
2017-04-26 12:32:10.413 runtimeDemo[1194:22584480] rootmeta2 address:0x105da8e38
2017-04-26 12:32:10.413 runtimeDemo[1194:22584480] nilclass address:0x0
2017-04-26 12:32:10.413 runtimeDemo[1194:22584480] superrootmeta address:0x105da8e88
通過結(jié)果可以看出,結(jié)果與圖示相符嫡秕。
FAQ:
1.class方法和object_getClass有區(qū)別么渴语?
細(xì)心的朋友可能發(fā)現(xiàn)了,上面有的時(shí)候用class方法淘菩,有的時(shí)候用object_getClass方法遵班。讓我們看一下源碼
+ (Class)class {
return self;
}
- (Class)class {
return object_getClass(self);
}
- 類方法class屠升,返回的是self潮改,所以當(dāng)查找meta class時(shí),需要對類對象調(diào)用object_getClass方法
- 實(shí)例方法class腹暖,內(nèi)部實(shí)現(xiàn)就是調(diào)用的object_getClass方法汇在,
即實(shí)例對象調(diào)用class,或?qū)?shí)例對象使用object_getClass()時(shí)脏答,返回的確實(shí)是實(shí)例對象的cls糕殉,但實(shí)例對象內(nèi)部的cls保存的是類對象,而不是meta class
ps: 附上一些有關(guān)meta class的文章
http://www.reibang.com/p/45fe90253519
http://blog.csdn.net/beclosedtomyheart/article/details/50164353
http://blog.csdn.net/windyitian/article/details/19810875