元类(meta class)

元类(meta class),这个名字想必很多人都听过,网上也有很多关于元类的介绍,今天我就按照自己这两天的理解来简单探讨一下这个玩意,有误之处还望指出。

首先,下载objc源码,源码地址:https://opensource.apple.com/tarballs/objc4/
打开链接后会发现有很多版本,我直接下载的最新版(709版本)

认识NSObject

1.打开objc工程的NSObject.h,找到NSObject类的定义
@interface NSObject <NSObject> {
    Class isa  OBJC_ISA_AVAILABILITY;  //发现NSObject包含一个Class对象
}

2.继续查看Class类型
typedef struct objc_class *Class;

3.继续查看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;  //这个东西好像很牛逼,继续看一下
    ...
}

5.查看isa_t类型
union isa_t 
{
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    Class cls;    //诶,这个东西又出现了
    uintptr_t bits;
}

简单用图片表示一下:


图-1

那么简单总结一下就是,NSObject包含一个Class,Class中包含一个superclass和cls

meta class 获取

1.打开objc工程的runtime.h,找到meta class的获取接口
Class objc_getMetaClass(const char *name) {
    //下面代码进行了简化
    //1.通过类名找到类对象(注意不是类实例对象)
    Class cls = objc_getClass (aClassName);
    //2.返回上面图-1中最里面的cls
    return cls->isa.cls;
}

2.meta class的获取其实就是获取类对象包含的cls,而我们在实际开发中是不能调用到cls的,这时,可以通过object_getClass来实现。
查看object_getClass的实现
Class object_getClass(id obj) {
    //下面代码经过简化
    return obj->isa.cls;  //也是返回cls
}

通过测试代码来分析源码

//引入rumtime头文件
#import <objc/objc-runtime.h>
//定义一个简单的类
@interface Father : NSObject
@property (nonatomic, strong) NSString *name;
@end
//各种实例打印
    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]));

打印结果:

打印结果:
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

通过结果进行分析:

  • 类实例对象本身不是元类
  • 类实例对象通过class方法获取到的对象为类对象,[f class] == [Father class]
  • 通过类对象调用的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);

打印结果

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

通过结果可以看出,结果与图示相符。

FAQ:
1.class方法和object_getClass有区别么?
细心的朋友可能发现了,上面有的时候用class方法,有的时候用object_getClass方法。让我们看一下源码

+ (Class)class {
    return self;
}
- (Class)class {
    return object_getClass(self);
}
  • 类方法class,返回的是self,所以当查找meta class时,需要对类对象调用object_getClass方法
  • 实例方法class,内部实现就是调用的object_getClass方法,
    即实例对象调用class,或对实例对象使用object_getClass()时,返回的确实是实例对象的cls,但实例对象内部的cls保存的是类对象,而不是meta class

ps: 附上一些有关meta class的文章
http://www.jianshu.com/p/45fe90253519
http://blog.csdn.net/beclosedtomyheart/article/details/50164353
http://blog.csdn.net/windyitian/article/details/19810875

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容