1

在 Objective-C 运行时,为什么 method_getNumberOfArguments 返回的结果比选择器暗示的多两个结果?

例如,为什么@selector(initWithPrice:color:) 返回 4?

4

2 回答 2

6

TL;博士

好的。只是为了澄清事实,是的,任何objective-c方法的前两个参数都是selfand _cmd,总是按照这个顺序。

Objective-C 的简史

然而,更有趣的主题是为什么会出现这种情况。为此,我们必须先回顾一下 objc 的历史。事不宜迟,让我们开始吧。

早在 1983 年,objective-c 的“上帝”Brad Cox 想要在 C之上创建一种面向对象的基于运行时的语言,以实现跨平台的良好性能和灵活性。结果,最初的 Objective-C“编译器”只是将 Objective-C 源代码转换为 C 运行时等效项的简单预处理器,然后使用特定于平台的 C 编译器工具进行编译。

然而,C 并不是为对象而设计的,这是 Objective-C 必须克服的最基本的东西。虽然 C 是一种健壮且灵活的语言,但运行时支持是它的关键缺陷之一。

在 Objective-C 的早期设计阶段,决定对象将是一个纯粹的基于堆的指针设计,这样它们就可以在任何函数之间传递而没有奇怪的复制语义等(这在 Obj-C++ 中有所改变和 ARC,但这对于这篇文章来说范围太广了),并且每个方法都应该是自我意识的(实际上,正如 bbum 所指出的,这是使用与原始函数调用相同的堆栈帧的优化),所以理论上,您可以将多个方法名称映射到同一个选择器,如下所示:

// this is a completely valid objc 1.0 method declaration
void *nameOrAge(id self, SEL _cmd) {
    if (_cmd == @selector(name)) {
        return "Richard";
    } 
    if (_cmd == @selector(age)) {
        return (void *) (intptr_t) 16;
    }

    return NULL;
}

那么这个函数理论上可以映射到两个选择器,nameage,并根据调用哪个选择器执行条件代码。在一般的 Objective-C 代码中,这并不是什么大不了的事,因为现在 ARC 很难将函数映射到选择器,由于强制转换等,但是从那时起语言已经发展了很多。

希望这可以帮助您理解Objective-C 方法的两个“不可见”参数背后的原因,第一个是被调用的对象,第二个是在该对象上调用的方法。

于 2012-12-23T13:40:40.127 回答
2

前两个参数是隐藏参数 self 和 _cmd。

于 2012-12-23T12:57:48.593 回答