11

我对 Objective-C 中的动态类型如何工作很感兴趣。我一直在研究“id”类型,我知道它的作用以及如何使用它,但我很好奇……这样的功能是如何在幕后实现的?

您无法在编译期间确定/解决任何问题,只能在运行时确定/解决。我想它可以简单地指向内存中某个对象的第一个字节,但是类签名是如何存储的呢?它如何知道它当前指向什么以及它如何为指向对象的类实现各种 getter?

4

2 回答 2

15

“在幕后”,可以这么说,所有的 Objective-C 对象都是 C 结构,带有一个指向代表其类型的 Class 对象的指针。Anid是指向最基本的此类结构的指针,它看起来像这样:

struct objc_object {
    Class isa;
}

id编译器会对其进行特殊处理,因为编译器不会向您发出任何警告,表明对象可能不会像使用更强类型的变量时那样响应任何选择器。

当您在任何对象上调用方法时,它会跟随isa指向 Class 对象的指针并在该 Class 对象中查找您尝试调用的方法的选择器的实现函数。

于 2011-04-05T17:41:48.757 回答
7

为了补充 Anomie 的答案,一个类如何存储它回答的消息以及这些消息调用的代码位的表是完全不透明的。所以在某种程度上没有人能准确地回答 Apple 的实现是如何工作的,而且几乎可以肯定它与 GNU 的实现不同。

但是,Apple 的Objective-C 运行时参考解释了运行时可以在 C 级别执行的所有操作。因此,您可以看到可以进行哪些操作来设置和查找内容。这是一个相对简单的系统,主要只是一堆字典(在未变形的意义上),它们将一个事物映射到另一个事物,例如从选择器到 IMP 函数指针。如果表中有特定类的条目,则调用相关的事物。如果不是,则检查超类,考虑标准的forwardingTargetForSelector:回退机制,依此类推。

除此之外,更具体的评论需要更具体的问题。有很多细节,比如键值观察是通过方法 swizzle 实现的(因此,运行时调整 C 指针,该类将调用 setter 以调用真正的 setter 并通知正在观察的人),但是它们都只是记录在案的运行时的特殊用途。

于 2011-04-05T18:42:52.743 回答