Objective-C 2.0 运行时系统编程

1 概述

Objective-C语言将决定尽可能的从编译和链接时推迟到运行时。只要有可能,Objective-C总是使用动态的方式来解决问题。这意味着Objective-C语言不仅需要一个编译器,同时也需要一个运行时系统来执行编译好的代码。这里的运行时系统扮演的角色类似于 Objective-C语言的操作系统,Objective-C基于该系统来工作。
本文章将具体介绍NSObject类以及Objective-C程序是如何与运行时系统交互的。特别地,本文章还给出来怎样在运行时动态地加载新类和将消息转发给其它对象的范例,同时也给出了怎样在程序运行时获取对象信息的方法。
通常,如果仅仅写一个Cocoa 程序,程序员不需要知道和理解Objective-C运行时系统的底层细节,但这篇文章仍然值得推荐阅读,以了解 Objective-C运行时系统的原理,并能更好的利用 Objective-C的优点。

2 参考

《Objective-C 2.0 运行时系统参考库》描述了Objective-C运行库的数据结构和函数接口。程序可以通过这些接口来和Objective-C运行时系统交互。例如,您可以增加一个类或者方法,或者获得所有类的定义列表等。
《Objective-C 2.0 程序设计语言》介绍了Objective-C语言本身。
《Objective-C 版本说明》给出了在最近版本的Mac OS X系统中关于Objective-C运行时系统的一些改动。

3 运行时系统的版本和平台

在不同的平台上Objective-C运行时系统的版本也不相同。

3.1早期版本和现行版本

Objective-C运行时系统有两个已知版本:早期版本和现行版本。
现行版本主要是Objective-C 2.0 及与其相关的新特性。早期版本的编程接口见《Objective-C 1运行时系统参考库》;现行版本的编程接口见《Objective-C 2.0 运行时系统参考库》。
在现行版本中,最显著的新特性就是实例变量是“健壮(non-fragile )的”:
1)在早期版本中,如果您改变类中实例变量的布局,您必须重新编译该类的所有子类。
2)在现行版本中,如果您改变类中实例变量的布局,您无需重新编译该类的任何子类。
此外,现行版本支持声明property 的synthesis属性(参考《Objective-C 2.0 程序设计语言》的“属性”一节)。

3.2平台

iPhone 程序和Mac OS X 10.5及以后的系统中的64位程序使用的都是Objective-C运行时系统的现行版本。
其它情况(Mac OS X系统中的32位程序)使用的是早期版本。

4 和运行时系统的交互

Objective-C程序有三种途径和运行时系统交互:
1)通过 Objective-C源代码;
2)通过 Foundation框架中类NSObject的方法;
3)通过直接调用运行时系统的函数。

4.1通过Objective-C源代码

大部分情况下,运行时系统在后台自动运行,您只需编写和编译Objective-C源代码。
当您编译Objective-C类和方法时,编译器为实现语言动态特性将自动创建一些数据结构和函数。这些数据结构包含类定义和协议类定义中的信息,如在《Objective-C 2.0 程序设计语言》中“定义类”和“协议类”一节所讨论的类的对象和协议类的对象,方法选标,实例变量模板,以及其它来自于源代码的信息。运行时系统的主要功能就是根据源代码中的表达式发送消息,如“消息”一节所述。

4.2通过类NSObject的方法

Cocoa 程序中绝大部分类都是NSObject类的子类,所以大部分都继承了NSObject类的方法,因而继承了NSObject的行为。(NSProxy类是个例外;更多细节参考“消息转发”一节。)然而,某些情况下,NSObject类仅仅定义了完成某件事情的模板,而没有提供所有需要的代码。
例如,NSObject类定义了description 方法,返回该类内容的字符串表示。这主要是用来调试程序——GDB中的print-object方法就是直接打印出该方法返回的字符串。NSObject类中该方法的实现并不知道子类中的内容,所以它只是返回类的名字和对象的地址。NSObject的子类可以重新实现该方法以提供更多的信息。例如,NSArray 类改写了该方法来返回NSArray 类包含的每个对象的内容。
某些NSObject的方法只是简单地从运行时系统中获得信息,从而允许对象进行一定程度的自我检查。例如,