Objective-C 不需要知道接收器的类型。在运行时,所有对象都是 just id
,并且一切都是动态调度的。因此,任何消息都可以发送到任何对象,无论其类型如何。(在运行时,对象可以自由决定如何处理他们不理解的消息。最常见的做法是引发异常并崩溃,但有许多类型的对象可以处理不理解的任意消息。 t 直接映射到方法调用。)
然而,有一些技术细节使这变得复杂。
ABI(应用程序二进制接口)定义了返回某些原始类型的不同机制。只要该值是“一个字大小的整数”,那么就没有关系(这包括诸如NSInteger
和所有指针之类的东西,这意味着扩展所有对象)。但是在某些处理器上,浮点数在与整数不同的寄存器中返回,并且结构(如CGRect
)可能会根据其大小以多种方式返回。为了编写必要的汇编语言,编译器必须知道返回值的类型。
ARC 增加了额外的皱纹,要求编译器更多地了解参数的类型(特别是它们是对象还是原语),以及是否需要考虑任何内存管理属性。
编译器并不真正关心什么是“真实”类型test
,只要它能够弄清楚-count
. 因此,在处理一个id
值时,它会查看它可以看到的每个已知选择器(即在包含的标头或当前定义的每个选择器.m
)。如果他们中的许多人在不同的班级中,那很好,只要他们都同意。但是如果它根本找不到选择器,或者如果某些接口不同意,那么它就无法编译该行代码。
正如 lobstah 所指出的,您可能在 Swift 代码中的某个地方有一个类型,该类型具有一个被调用的@objc
方法count()
或一个@objc
名为的属性count
,它返回的东西不是Int
(映射到NSInteger
,因此匹配通常的签名-count
)。您需要修复该方法,或者您需要从 ObjC 中隐藏它(例如,通过添加@nonobjc
)。
或者更好:去掉id
, 并使用它的实际类型。id
在 Cocoa 中通常是一个坏主意,尤其是如果您在其上调用方法,则尤其是一个坏主意,因为编译器无法检查对象是否会响应并且您可能会崩溃。