笔者翻译自[objc explain]: Classes and metaclasses
Object-C 是基于类的对象系统。每一个对象都是一些类的实例;这个对象的 isa 指针指向它所属的类。该类描述这个对象的数据信息:内存分配大小和实例变量的类型与布局。这个类也描述了对象的行为:它能够响应的选择器和它实现的实例方法。
类的方法列表是一个实例方法的集合,是对象响应的选择器。当你向一个实例发送一条消息,objc_msgSend()查询对象所属类(和它的父类,如果有)的方法列表,去决定调用哪个方法。
每个 Object-C 类也是一个对象。它有一个 isa 指针和其他数据,并且可以响应选择器。当你调用一个“类方法”,例如:[NSObject alloc],你实际上是向类对象发送了一条消息。
因为一个类是一个对象,它肯定也是其他类的实例,这个类是元类(metaclass)。元类是关于类对象的描述,就像类是普通实例对象的描述一样。实际上,元类的方法列表正是类方法:该类对象响应的选择器。当你向一个类(元类的实例)发送消息,objc_msgSend()查询元类(和它的父类,如果有)的方法列表,去决定调用哪个方法。元类为类对象描述类方法,就像类为实例对象描述实例方法一样。
元类?元类链是一直向下的吗?不是,一个元类是根元类的实例;根元类是它自身的实例。isa 指针链以一个环结束:实例指向类指向根元类指向根元类自身。元类的 isa 指针并不重要,因为在现实世界中,没人会向元类对象发送消息。
元类的父类就要更重要了。元类的父类链平行于类的父类链,因此类方法跟实例方法一样被继承。并且根元类的父类是根类,因此每个类对象都响应根类的实例方法。最后,一个类对象就像其他对象一样是根类的实例(或子类)。
晕了吧?这个图肯定会帮助你。记住,当一个消息被发送到任何对象,都会从对象的 isa 指针开始寻找应该调用的方法,然后继续沿着父类链向上寻找。“实例方法”被类定义,“类方法”被元类和根类(非元类)定义。
在合理的电脑科学语言理论中,一个类和元类的层次结构可以是更自由的形式,像更深的元类链以及任何单一的元类实例化多个类。Object-C 使用元类实现了类方法这样的实际目的,但在其他情况下趋向于隐藏元类。例如,[NSObject class]等价于[NSObject self],尽管按正常的理解它应该返回 NSObject->isa 指向的元类。Object-C 语言有一些实际情况的妥协,在这里,它不能得到类的实际结构,元类。