元类(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

元类(meta class)的更多相关文章

  1. django-model的元类Meta

    Meta类存在model类里面 模型元选项 文档有更多Meta类的配置属性: English:https://docs.djangoproject.com/en/1.11/ref/models/opt ...

  2. iOS中类、元类、isa详解

    类相信大家都知道是什么,如果看过runtime的源码或者看过相关的文章对isa肯定也不陌生,不过元类(meta class)大家可能就比较陌生了.不过大家也不要担心,我会细细道来,让大家明白它到底是个 ...

  3. Delphi 类引用 Class Reference 元类 MetaClass 用法

    delphi中类引用的使用实例 类引用类引用(Class Reference)是一种数据类型,有时又称为元类(MetaClass),是类的类型的引用.类引用的定义形式如下: class of type ...

  4. Python 元类详解

    一.Type介绍 在Python中一切皆对象,类它也是对象,而元类其实就是用来创建类的对象(由于一切皆对象,所以元类其实也是一个对象). 先来看这几个例子: 例1: In [1]: type(12) ...

  5. Python中的元类和__metaclass__

    1.什么是元类 元类让你来定义某些类是如何被创建的,从根本上说,赋予你如何创建类的控制权.可以把元类想成是一个类中类,或是一个类,它的实例是其它的类.当某个类调用type()函数时,你就会看到它到底是 ...

  6. Python元类实践--自己定义一个和collections中一样的namedtuple

    大家可能很熟悉在collections模块中有一个很好用的扩展数据类型-namedtuple. 如果你还不知道这个类型,那么请翻看标准手册. 我利用元类轻松定义一个namedtuple. 先把代码贴上 ...

  7. Python属性、方法和类管理系列之----元类

    元类的介绍 请看位于下面网址的一篇文章,写的相当好. http://blog.jobbole.com/21351/ 实例补充 class Meta(type): def __new__(meta, c ...

  8. Python的元类

    1.用元类验证子类 每当我们定义新类的时候,元类就会运行雅正代码,以确保这个新类符合规定的规范. Python系统把子类的class语句处理完毕,就会调用元类的 __new__ 方法.元类可以通过 _ ...

  9. Python中的元类(metaclass)

    推荐+收藏:深刻理解Python中的元类(metaclass) 做一些笔记学习学习: 在大多数编程语言中,类就是用来描述如何生成一个对象的代码段,在Python中类也是一个对象,这个(类)对象自身拥有 ...

随机推荐

  1. 【Java进阶】——初识数据库连接池

    [简介] 数据库连接池:程序启动时建立足够的数据库连接,并将这些连接组成一个连接池,由程序动态地对池中的链接进行申请,使用,释放. 相比之前的程序连接,减少了数据库的打开关闭次数,从而减少了程序响应的 ...

  2. Java中ArrayList,Vector,LinkedList,HashMap,HashTable,HashSet对比及总结

    1.所有的集合的父类都是Collection的接口 2.Set List Map 区别 A  在Set里面:无法添加元素的顺序,所以Set里面的元素不能重复 B  在List中:有索引号,类似于数组, ...

  3. 你不得不知的逻辑或(||)与(&&)非(!)

    最近重新翻开原生JS,又得到很多不同的体会,虽然现在开发框架那么多,但很多思想都还是离不开原生的基础.今天呢,我就根据自己的学习总结一下逻辑与(&&)和(逻辑或(||)和逻辑非(!). ...

  4. Laravel框架一:原理机制篇

    Laravel作为在国内国外都颇为流行的PHP框架,风格优雅,其拥有自己的一些特点.以下是本人一点粗浅的认识,不敢奢求他人同意,更不能一一而足,仅为自己做一点总结而已. 一. 请求周期 Laravel ...

  5. js中的IP格式正则匹配校验详解~

    IPV4的格式为x:y:z:w,其中{x,y,z,w}属于{0~255}的正整数: 下面是其校验的正则表达式: function isIP(ip) { var re =  /^(\d{1,2}|1\d ...

  6. 2017-4-26 winform 菜单和工具栏

    如何让radiobutton进行分组: 用Panel    相当于div 菜单和工具栏: MenuStrip(菜单条) ShortcutKeys-------------------------与菜单 ...

  7. Golang 在mac上用VSCode开发、Delve调试

    本文包含以下内容: 1.安装VSCode: 2.用Delve调试Go项目: 3.自定义代码片段: 1.安装VSCode 先去下载VSCode,这个链接里面也有官方文档. 安装插件: vscode-ic ...

  8. Linux Bootup Time

    Linux Bootup Time 英文原文地址:http://elinux.org/Boot_Time 1.   简介 启动时间这一话题包括很多子话题,比如启动时间的衡量.启动时间的分析.人为因素分 ...

  9. 蓝桥杯-打印十字图-java

    /* (程序头部注释开始) * 程序的版权和版本声明部分 * Copyright (c) 2016, 广州科技贸易职业学院信息工程系学生 * All rights reserved. * 文件名称: ...

  10. 关于IT创业和反思

    2016年8月的某一天本是世上平凡的一天,对于我而言却并不平凡. 这一天,我离开了待了近四年的创业公司.从它成立前的筹备开始,伴随着它的起起伏伏到完成C轮融资,从来没想过以这种方式离开,然而人生总是充 ...