原文地址:[objc explain]: Classes and metaclasses

原文作者:Greg Parker

译者:kirinzer

[译]objc 讲解: 类和元类

Objective-C 是一个基于类的对象系统。每一个对象都是类的实例。对象的 isa 指针指向它的类。这个类描述了对象的数据(分配的空间大小还有变量类型和布局)。并且这个类还描述了对象的实现,响应的选择器以及实现的实例方法。

类的方法列表是实例方法(对象响应的选择器)的集合。当你发送消息给一个实例,objc_msgSend() 会查找类的方法列表(以及父类,如果有的话)并确定需要调用哪一个方法。

每一个 Objective-C 类也是一个对象。它有一个 isa 指针还有其他的数据,并且也能响应选择器。当你调用一个类似 [NSObject alloc] 这个样的 “类方法” 时,你实际上是发送了消息给这个类(对象)。

既然类也是一个对象,那么它一定是其他类的实例,那个类就是元类 (metaclass)。元类是类(对象)的描述,就像类是普通实例的描述一样。特别的是,元类的方法列表是类方法(类响应的选择器)。当你发送消息给一个类(元类的实例),objc_msgSend() 会查找元类(已及它的父类)的方法列表并确定调用的方法。类方法是由类代表的元类所描述,如同实例方法是由实例对象对应的类(对象)来描述的。

你觉得元类是什么样的?到元类还会继续向下吗?不,元类其实是根类 (root class) 的元类的实例;这个根类的元类,实际上就是它自己。isa 链在这里结束,形成一个环形(实例->类->元类->根类->根类自己)。元类的 isa 指针的行为不是很重要,因为在现实世界中没人向元类发送消息。

更重要的是元类的父类,元类的父类链与类的父类链平行,所以,类方法和实例方法都会被继承。根类的元类的父类仍然是根类,因此每一个类都响应根类的实例方法。最后,类也是根类(子类)的实例,就像其他对象一样。

感到困惑吗?这个图也许会有所帮助。记得,当一个消息发送给任何一个对象时,将会由对象的 isa 指针开始查找方法,接着沿着父类链向上去查找。“实例方法” 被类定义,“类方法”被元类(以及不是元类的根类)定义。

在真正的计算机科学语言理论中,类和元类的分层结构能够有更自由的形式,通过更深层次的元类链以及单个元类的更多的实例。Objective-C 使用元类来实现比如类方法这样的目标,然而在别的方面却意图隐藏元类。例如,[NSObject class] 和 [NSObject self] 是一模一样的,即使在正式的条款中它应该返回一个 NSObject->isa 指向的元类。Objective-C 语言是一套可行的妥协方案。由于限制了类的模式,它才会变成这个样子。