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

时间: 2024-11-17 13:46:42

元类(meta class)的相关文章

Delphi 类引用 Class Reference 元类 MetaClass 用法

delphi中类引用的使用实例 类引用类引用(Class Reference)是一种数据类型,有时又称为元类(MetaClass),是类的类型的引用.类引用的定义形式如下: class of type 例如: type SomeClass = class of TObject; var AnyObj: SomeClass; TObject = class end; TClass = class of TObject; 下面的例子说明了类引用的用法: program Project1; {$APP

Python中的元类(metaclass)

推荐+收藏:深刻理解Python中的元类(metaclass) 做一些笔记学习学习: 在大多数编程语言中,类就是用来描述如何生成一个对象的代码段,在Python中类也是一个对象,这个(类)对象自身拥有创建对象(类实例)的能力. 因为它的本质是一个对象: 可以将它赋值给一个变量 可以拷贝它 增加属性 作为参数进行传递 可以在运行时动态地创建他们,可以在函数中创建类,只需要使用class关键字即可 当使用class关键字的时候,Python解释器会自动地创建这个对象,Python还提供了手动处理的方

python类:描述器Descriptors和元类MetaClasses

http://blog.csdn.net/pipisorry/article/details/50444769 描述器(Descriptors) 描述器决定了对象属性是如何被访问的.描述器的作用是定制当你想引用一个属性时所发生的操作. 构建描述器的方法是至少定义以下三个方法中的一个.需要注意,下文中的instance是包含被访问属性的对象实例,而owner则是被描述器修辞的类. __get__(self, instance, owner) – 这个方法是当属性被通过(value = obj.at

廖雪峰Python学习笔记——使用元类

元类(MetaClasses) 元类提供了一个改变Python类行为的有效方式. 元类的定义是"一个类的类".任何实例是它自己的类都是元类. class demo(object): pass obj = demo() print "Class of obj is {0}".format(obj.__class__) print "Class of obj is {0}".format(demo.__class__) # Class of obj

Python中的元类

从前面"Python对象"文章中了解到,在Python中一切都是对象,类可以创建实例对象,但是类本身也是对象. class C(object): pass c = C() print c.__class__ print C.__class__ 代码中,通过"__class__"属性来查看对象的类型,对于类C对象本身,它的类型是type. 由于类也是对象,所以就可以在运行时动态的创建类,那么这时候就要用到内建函数type了. 再看type 从前面的文章了解到,可以通过

Python——五分钟理解元类(metaclasses)

“元类的魔幻变化比 99% 的用户所担心的更多,当你搞不懂是否真的需要用它的时候,就是不需要.” —Tim Peters 本文源于在 PyCon UK 2008 上的一个快速演讲. 元类被称为 Python 中的“深奥的巫术”.尽管你需要用到它的地方极少(除非你基于zope 编程),可事实上它的基础理论其实令人惊讶地易懂. 一切皆对象 一切皆对象 一切都有类型 “class”和“type”之间本质上并无不同 类也是对象 它们的类型是 type 以前,术语 type 用于内置类型,而术语 clas

Python元类的一些应用

最近刚接触python的元类,网络上有比较详细的介绍,这里是在看Django时候发现一点关于元类的应用,做个笔记. from django.utils import six class A(type):     def __new__(cls, name, parents, attrs):         return type.__new__(cls, name, parents, attrs) class C(six.with_metaclass(A)):     pass 创建C类的时候,

元类应用ORM实现

首先看下一个简单的例子 # 需求 import numbers class Field: pass class IntField(Field): # 数据描述符 def __init__(self, db_column, min_value=None, max_value=None): self._value = None self.min_value = min_value self.max_value = max_value self.db_column = db_column if min

Pyhton中的元类

目录 前言 一切皆对象 动态的创建类 到底什么是元类 自定义元类 为什么要用metaclass类而不是函数 结语 前言 本片文章主要是StackOverflow上关于元类解释的高赞文章的译文,顺便加了一点个人的理解. 想看原文的同学可以直接点击 What-are-metaclasses-in-python. 环境使用Python2 一切皆对象 在Python中,一切皆对象. 字符串.列表.字典和函数是对象,类也是对象.因此你可以: 把类赋值给一个变量 可以拷贝它 可以为它添加属性 可以把它作为一