(原文出处:Objective-C Internals | Always Processing)

Objective-C有一个独特的类结构,其中类是目标。它的高雅规划允许经过运用编译器生成的元类对所有目标类型进行动态办法派发。

Objective-C,像许多流行的编程言语相同,选用基于类的面向目标编程风格。为了评论Objective-C的类架构,咱们将重点放在类的行为(办法和特点)上,暂时不触及类的状况(即实例变量,在本文中不触及)。

虽然特点供给了对类状况的拜访,但在Objective-C中它们仅仅办法的语法糖。(这个话题能够在之后的文章里评论)

以下六行代码足以探索Objective-C的类架构:

@interface MyObject: NSObject
+ (void)classMethod;o
- (void)instanceMethod;
@end
MyObject *object = [[MyObject alloc] init];

办法派发

上述最后一行实例化了类MyObject,并将新的目标实例赋值给变量object。新的目标实例具有自己的状况,并且能够呼应音讯(即办法调用),例如-instanceMethod和-init。

Objective-C对每个音讯发送(即每个办法调用)运用动态派发[1]。运行时经过在实例的isa变量所引用的类目标中查找选择器(即办法名)来找到办法完成。(所有Objective-C目标中的第一个实例变量是isa指针,它由编译器主动刺进并由运行时初始化。)

前面阶段中运用类目标这个术语是有意义的:在Objective-C中,类也是目标!这个奇妙的规划是类办法言语特性的根底(例如调用[NSObject alloc]或[MyObject classMethod]):它使得类办法能够彻底多态(即子类能够重写类办法),并且消除了类办法和实例办法之间的运行时差异(类办法和实例办法都经过objc_msgSend进行派发)。

由于类也是目标,它们也有一个isa指针,指向元类。元类为类目标供给了选择器到类办法完成的映射,就像类目标为类实例(即目标)供给选择器到实例办法完成的映射相同。

承继

任何类或元类只为类完成的办法供给选择器到办法完成的映射。在上面的代码示例中,MyObject的类目标具有instanceMethod的映射,而MyObject的元类具有classMethod的映射。

MyObject还呼应于+alloc和-init,这些办法在NSObject中完成。每个类目标(包含每个元类)都有一个指向其超类的引用。在解析选择器时,如果类/元类目标没有界说映射,运行时会在下一个超类中搜索界说。(虽然运行时供给了对反常的处理办法,但如果在超类链的末尾找不到界说,运行时仍将抛出反常。)

架构图

下面的图示说明晰上面评论的Objective-C类的规划:

[翻译]Objective-C内部探秘1:类架构

目标实例有一个isa变量,指向MyClass类目标。

MyClass类目标有:

  • 一个isa变量,指向MyClass元类。
  • 一个super变量,指向NSObject类目标。

MyClass元类有:

  • 一个isa变量,指向NSObject(根目标)元类。
  • 一个super变量,指向NSObject元类。

图中还显现了一些上述评论未涵盖的细节:

  • 每个元类的isa变量都指向根目标的元类,包含根目标元类自身。isa变量不为nil是有意义的(目标必须有某种类型),但我不确定为什么所有元类的类型都是根元类的类型,而不是运行时供给的类型。不过,实际上这并不重要,由于元类自身永远不会接纳音讯。
  • 根元类的超类是根类目标。当我在研讨图示时,这一点让我感到惊奇。我一开始并没有明确地理解为什么会存在这个链接,我认为它的超类会是nil。