元类(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;
}
简单用图片表示一下:
那么简单总结一下就是,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 继承
这是一张很牛逼的图,我们用尽量简单的代码来测试一下:
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)的更多相关文章
- django-model的元类Meta
Meta类存在model类里面 模型元选项 文档有更多Meta类的配置属性: English:https://docs.djangoproject.com/en/1.11/ref/models/opt ...
- iOS中类、元类、isa详解
类相信大家都知道是什么,如果看过runtime的源码或者看过相关的文章对isa肯定也不陌生,不过元类(meta class)大家可能就比较陌生了.不过大家也不要担心,我会细细道来,让大家明白它到底是个 ...
- Delphi 类引用 Class Reference 元类 MetaClass 用法
delphi中类引用的使用实例 类引用类引用(Class Reference)是一种数据类型,有时又称为元类(MetaClass),是类的类型的引用.类引用的定义形式如下: class of type ...
- Python 元类详解
一.Type介绍 在Python中一切皆对象,类它也是对象,而元类其实就是用来创建类的对象(由于一切皆对象,所以元类其实也是一个对象). 先来看这几个例子: 例1: In [1]: type(12) ...
- Python中的元类和__metaclass__
1.什么是元类 元类让你来定义某些类是如何被创建的,从根本上说,赋予你如何创建类的控制权.可以把元类想成是一个类中类,或是一个类,它的实例是其它的类.当某个类调用type()函数时,你就会看到它到底是 ...
- Python元类实践--自己定义一个和collections中一样的namedtuple
大家可能很熟悉在collections模块中有一个很好用的扩展数据类型-namedtuple. 如果你还不知道这个类型,那么请翻看标准手册. 我利用元类轻松定义一个namedtuple. 先把代码贴上 ...
- Python属性、方法和类管理系列之----元类
元类的介绍 请看位于下面网址的一篇文章,写的相当好. http://blog.jobbole.com/21351/ 实例补充 class Meta(type): def __new__(meta, c ...
- Python的元类
1.用元类验证子类 每当我们定义新类的时候,元类就会运行雅正代码,以确保这个新类符合规定的规范. Python系统把子类的class语句处理完毕,就会调用元类的 __new__ 方法.元类可以通过 _ ...
- Python中的元类(metaclass)
推荐+收藏:深刻理解Python中的元类(metaclass) 做一些笔记学习学习: 在大多数编程语言中,类就是用来描述如何生成一个对象的代码段,在Python中类也是一个对象,这个(类)对象自身拥有 ...
随机推荐
- Netd学习笔记
service netd /system/bin/netd class main socket netd stream 0660 root system socket dnsp ...
- 不可不知的 Android strings.xml 那些事
相信 strings.xml 已经是大家在 Android 开发中最熟悉的文件之一了,但其实它也有很多需要注意的地方和一些小技巧,知道了这些可以让你的 Android 应用更加规范易用,大家来看看吧. ...
- C++中的类继承(1) 三种继承方式
继承是使代码可以复用的重要手段,也是面向对象程序设计的核心思想之一.简单的说,继承是指一个对象直接使用另一对象的属性和方法.继承呈现了 面向对象程序设 计的层次结构, 体现了 由简单到复杂的认知过程. ...
- 关于Form表单一些基础知识
1.两个重要属性: action:表单需要提交的服务器地址 method:表单提交数据使用的方法,get/post >>>get和post的区别 ①get传参使用URL传递,所有参数 ...
- jdk1.8新特性,还不知道的朋友还不看看,1.9都快出来了
一.接口的默认方法 Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用 default关键字即可,这个特征又叫做扩展方法,示例如下:代码如下:interface Formula { ...
- EasyMvc--让MVC区域开发更Easy(提供源码下载)
核心: 主要利用MVC的区域功能,实现项目模块独立开发和调试. 目标: 各个模块以独立MVC应用程序存在,即模块可独立开发和调试. 动态注册各个模块路由. 一:新建解决方案目录结构 如图: 二:Eas ...
- Unity Debug类
静态变量 developerConsoleVisible 报告是否开发控制台是可见的.开发控制台不能出现使用: isDebugBuild 在构建设置对话框中有一个叫做"发展构建"复 ...
- seajs模块标识命名和解析规则
模块标识采用路径形式,但要注意与路径的区别.require.require.async的第一个参数是模块标识.而seajs.use第一个参数为文件路径. use是全局的,require是局部的.模块标 ...
- 博弈论(Game Theory) - 01 - 前传之占优战略均衡
博弈论(Game Theory) - 01 - 前传之占优战略均衡 开始 我们现在准备攀爬博弈论的几座高峰. 我们先看看在纳什均衡产生之前,博弈论的发展情况. 我们的第一座高峰是占优战略均衡. 囚徒困 ...
- 「七天自制PHP框架」第三天:PHP实现的设计模式
往期回顾:「七天自制PHP框架」第二天:模型与数据库,点击此处 原文地址:http://www.cnblogs.com/sweng/p/6624845.html,欢迎关注:编程老头 为什么要使用设计模 ...