【问题标题】:Why does the Objective-C compiler need to know method signatures?为什么 Objective-C 编译器需要知道方法签名?
【发布时间】:2015-01-05 18:59:32
【问题描述】:

为什么 Objective-C 编译器需要在编译时知道将在对象上调用的方法的签名,而它可以将其推迟到运行时(即动态绑定)?比如我写[foo someMethod],为什么编译器需要知道someMethod的签名呢?

【问题讨论】:

  • 据我了解,Objc 喜欢在运行前捕获此类潜在错误(因为这会导致崩溃),因此它更加强调预编译错误检查。
  • 如果您声明一个指向特定类对象的指针,编译器将验证该类是否实现了使用该指针调用的任何方法。如果您将其声明为简单的id,编译器将仅验证命名方法是否存在某处
  • 第一个问题很好;欢迎来到 Stack Overflow!

标签: objective-c objective-c-runtime method-signature


【解决方案1】:

因为调用约定最少(使用 ARC,原因更多,但调用约定一直是个问题)。

您可能已经被告知[foo someMethod] 被转换为函数调用:

objc_msgSend(foo, @selector(someMethod))

然而,这并不是完全正确的。根据返回的内容,它可能会转换为许多不同的函数调用(无论您是否使用结果,返回的内容都很重要)。例如,如果它返回一个对象或一个整数,它将使用objc_msgSend,但如果它返回一个结构(在 ARM 和 Intel 上),它将使用 objc_msgSend_stret,如果它在 Intel 上返回一个浮点数(但我相信不是 ARM),它将使用objc_msgSend_fpret。这都是因为在不同的处理器上,调用约定(如何设置堆栈和寄存器,以及存储结果的位置)因结果而异。

参数是什么以及有多少也很重要(可以从 ObjC 方法名称中推断出数量,除非它们是可变参数……对,你也必须处理可变参数)。在某些处理器上,前几个参数可能会放在寄存器中,而后面的参数可能会放在堆栈中。如果您的函数采用可变参数,那么调用约定可能仍然不同。为了编译函数调用,所有这些都必须知道。

ObjC 可以实现为更纯粹的对象模型来避免所有这些(就像其他更动态的语言一样),但这会以性能为代价(空间和时间)。考虑到动态调度的级别,ObjC 可以使方法调用的成本低得惊人,并且可以轻松地与纯 C 机器类型一起工作,但这样做的代价是我们必须让编译器了解有关我们方法签名的更多细节。

顺便说一句,这可能(并且经常如此)导致非常可怕的错误。如果您有几种方法:

- (MyPointObject *)point;

- (CGPoint)point;

也许它们在完全不同的文件中定义为不同类的方法。但是,如果编译器选择了错误的定义(例如当您向id 发送消息时),那么您从-point 返回的结果可能完全是垃圾。这是一个非常非常难以确定何时发生的错误(我也遇到过)。

如需了解更多背景信息,您可能会喜欢 Greg Parker 的 article explaining objc_msgSend_stretobjc_msgSend_fpret。 Mike Ash 也有an excellent introduction 来讨论这个话题。如果你想深入这个兔子洞,你可以看看 bbum 的instruction-by-instruction investigation of objc_msgSend。它现在已经过时,在 ARC 之前,并且仅涵盖 x86_64(因为每个架构都需要自己的实现),但仍然具有很高的教育意义和推荐。

【讨论】:

  • 好吧,我看到了,我在一篇文章中看到,objective-c 编译器在调用 .例如 int result = [obj foo:@"hello"];转换为 int result = ((int (*)(id, SEL, NSString *))objc_msgSend)(obj, @selector(foo:), @"hello");这是真的吗?
  • link请看这篇文章。
  • 没错,但您不应该误读。强制转换只是“将这些字节视为这种类型”。这是在编译时发生的事情,而不是运行时(它不是转换)。这是“将返回一个 int”而不是“将其转换为一个 int”的声明。仔细阅读迈克的盒子,其中包括“坏事发生”。 Mike 还掩盖了结构和浮点返回的特殊情况,它们是特定于体系结构的,而不是他所提出的观点所必需的。您可能对mikeash.com/pyblog/…感兴趣
  • 在末尾添加了更多链接。
  • 对于那些已经轻轻飘到兔子洞底部的人,current versions of objc_msgSend() are open source
猜你喜欢
  • 2011-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-16
  • 1970-01-01
  • 2010-09-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多