Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么Objective-C编译器需要知道方法签名?_Objective C_Objective C Runtime_Method Signature - Fatal编程技术网

为什么Objective-C编译器需要知道方法签名?

为什么Objective-C编译器需要知道方法签名?,objective-c,objective-c-runtime,method-signature,Objective C,Objective C Runtime,Method Signature,为什么Objective-C编译器需要在编译时知道将在对象上调用的方法的签名,而它可以将该签名推迟到运行时(即动态绑定)?例如,如果我编写[foo somethod],为什么编译器需要知道somethod的签名 因为至少要调用约定(对于ARC,原因更多,但调用约定一直是个问题) 您可能被告知,[foo someMethod]已转换为函数调用: objc_msgSend(foo, @selector(someMethod)) 然而,这并不完全正确。根据返回的内容,可以将其转换为许多不同的函数调用

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

因为至少要调用约定(对于ARC,原因更多,但调用约定一直是个问题)

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

objc_msgSend(foo, @selector(someMethod))
然而,这并不完全正确。根据返回的内容,可以将其转换为许多不同的函数调用(返回的内容与是否使用结果有关)。例如,如果它返回一个对象或整数,它将使用
objc\u msgSend
,但如果它返回一个结构(在ARM和Intel上),它将使用
objc\u msgSend\u stretc
,如果它在Intel上返回一个浮点(我相信不是ARM),它将使用
objc\u msgSend\u fpret
。这都是因为在不同的处理器上,调用约定(如何设置堆栈和寄存器,以及结果存储在何处)因结果而异

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

ObjC可以作为一个更纯粹的对象模型来实现,以避免所有这一切(就像其他更具动态性的语言一样),但这将以性能为代价(空间和时间)。考虑到动态调度的级别,ObjC可以使方法调用出奇地便宜,并且可以轻松地处理纯C机器类型,但是这样做的代价是我们必须让编译器知道关于方法签名的更多细节

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

- (MyPointObject *)point;

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


如果你想了解更多的背景知识,你可能会喜欢格雷格·帕克的和。迈克·阿什也对这个话题感兴趣。如果你想深入这个兔子洞,你可以看到bbum的。它现在已经过时了,是ARC之前的版本,只涵盖x86_64(因为每个体系结构都需要自己的实现),但它仍然具有很高的教育性和推荐性。

据我所知,Objc喜欢在运行前捕获此类潜在错误(因为它会导致崩溃),因此,它更加强调编译前的错误检查。如果您声明一个指针指向某个特定类的对象,编译器将验证该类是否实现了使用该指针调用的任何方法。如果您将其声明为简单的
id
,编译器将只验证命名方法是否存在;欢迎来到堆栈溢出!好的,我知道了,我在一篇文章中看到objective-c编译器在调用之前使用methode签名来强制转换objc_msgSend()。例如int result=[obj foo:@“hello”];转换为int result=((int(*)(id,SEL,NSString*)objc_msgSend)(obj,@selector(foo:),@“hello”);这是真的吗?请看这篇文章。这是正确的,但你不应该误读这篇文章。强制转换只是“将这些字节视为这种类型”,它发生在编译时,而不是运行时(不是转换)。这是一个“将返回一个int”而不是“将其转换为int”的语句。仔细阅读Mike的方框,其中包括“坏事情发生”。Mike还对结构和浮点返回的特殊情况进行了润色,这是特定于体系结构的,不是他提出的观点所必需的。你可能会对在结尾添加更多的链接感兴趣。对于那些已经轻轻飘到兔子洞底部的人,请点击。