元类(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. Netd学习笔记

    service netd /system/bin/netd     class main     socket netd stream 0660 root system     socket dnsp ...

  2. 不可不知的 Android strings.xml 那些事

    相信 strings.xml 已经是大家在 Android 开发中最熟悉的文件之一了,但其实它也有很多需要注意的地方和一些小技巧,知道了这些可以让你的 Android 应用更加规范易用,大家来看看吧. ...

  3. C++中的类继承(1) 三种继承方式

    继承是使代码可以复用的重要手段,也是面向对象程序设计的核心思想之一.简单的说,继承是指一个对象直接使用另一对象的属性和方法.继承呈现了 面向对象程序设 计的层次结构, 体现了 由简单到复杂的认知过程. ...

  4. 关于Form表单一些基础知识

    1.两个重要属性: action:表单需要提交的服务器地址 method:表单提交数据使用的方法,get/post >>>get和post的区别 ①get传参使用URL传递,所有参数 ...

  5. jdk1.8新特性,还不知道的朋友还不看看,1.9都快出来了

    一.接口的默认方法 Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用 default关键字即可,这个特征又叫做扩展方法,示例如下:代码如下:interface Formula {     ...

  6. EasyMvc--让MVC区域开发更Easy(提供源码下载)

    核心: 主要利用MVC的区域功能,实现项目模块独立开发和调试. 目标: 各个模块以独立MVC应用程序存在,即模块可独立开发和调试. 动态注册各个模块路由. 一:新建解决方案目录结构 如图: 二:Eas ...

  7. Unity Debug类

    静态变量 developerConsoleVisible 报告是否开发控制台是可见的.开发控制台不能出现使用: isDebugBuild 在构建设置对话框中有一个叫做"发展构建"复 ...

  8. seajs模块标识命名和解析规则

    模块标识采用路径形式,但要注意与路径的区别.require.require.async的第一个参数是模块标识.而seajs.use第一个参数为文件路径. use是全局的,require是局部的.模块标 ...

  9. 博弈论(Game Theory) - 01 - 前传之占优战略均衡

    博弈论(Game Theory) - 01 - 前传之占优战略均衡 开始 我们现在准备攀爬博弈论的几座高峰. 我们先看看在纳什均衡产生之前,博弈论的发展情况. 我们的第一座高峰是占优战略均衡. 囚徒困 ...

  10. 「七天自制PHP框架」第三天:PHP实现的设计模式

    往期回顾:「七天自制PHP框架」第二天:模型与数据库,点击此处 原文地址:http://www.cnblogs.com/sweng/p/6624845.html,欢迎关注:编程老头 为什么要使用设计模 ...