用 isa 承载对象的类信息

451 查看

 Effective Objective-C 2.0 – 52 Specific Ways to Improve Your iOS and OS X Programs 一书中,tip 14 中提到了,运行时检查对象类型自省 (Introspection) 特性。那么先来说说 自省反射 的定义是什么。

自省与反射的简单认识

第一次听说这两个概念,是在 Thinking in Java (4th Edition) 中的,而深入学习他们则是在 Python 语言的学习中,以下我用 Python 来举例说明。

wikipedia: In computer science, reflection is the ability of a computer program to examine and modify its own structure and behavior (specifically the values, meta-data, properties and functions) at runtime.

反射(Reflection) 是指计算机程序可以在运行时动态监测并修改它自己的结构和行为,比如值、元数据、属性和函数等的能力。通过反射,可以在运行时动态监测、生成、修改自己实际执行的等效代码。

两种方法可以达到同样的效果。但是,第一种方法是我们所说的常规方法,创建 HelloClass 这个 class 的一个实例,然后调用其中的方法。第二种我们用到了反射机制,通过 globals() 这个字典中来查找 HelloClass 这个类,并加以参数进行实例化于 obj,之后通过 getattr 函数获得 say_hello 方法,传参调用。

反射的好处在于,class_namemethod 变量的值可以在运行时获取或者修改,这样可以动态地改变程序的行为。

wikipedia: In computing, type introspection is the ability of a program to examine the type or properties of an object at runtime.

自省(Introspection) 是程序在运行时检测自己的某个对象的类型或者属性、方法的能力。例如在 Python 中的 dir 方法。

通过 dir() 函数从而做到自省,它可以返回某个对象的所有属性、方法等列表。

通过上述简单描述,我们大概知道了反射其实是包含着自省能力的,不仅可以获取到对象的各种属性信息,而且还可以动态修改自身的结构和行为。

objc_class 结构

在 ObjC 中,也支持在运行时检查对象类型这一操作,并且这个特性是内置于 Foundation 框架的 NSObject 协议中的。凡是公共基类(Common Root Class),即 NSObject 或 NSProxy ,继承而来的对象都要遵循此协议。

虽然 ObjC 支持自省这一特性,就一定会对 Class 信息做存储。这里我们便要引出 isa 指针。倘若对 ObjC 有一定的学习基础,都会知道 Objective-C 对象都可以通过 clang 进行 c 的语法格式转换,从而以 struct 来描述。所有的对象中都有一个 isa 指针,其含义是: it is a object! 而在最新的 runtime 库中,其 isa 指针的结构已经发生了变化。

以下代码均参考 runtime 版本为 objc4-680.tar.gz

会发现在 objc_object 这个基类中只有一个成员,即 isa_t 联合体(union) 类型的 isa 成员。而对于类对象的定义,可以从 objc_class 查看其结构: