5

将 master 合并到我的工作分支后,我在线上遇到了编译器错误,该错误没有被更改。错误看起来像

id test;
[test count];

发现多个名为“count”的方法结果不匹配。

起初看起来很清楚,因为编译器不知道“test”变量是哪种具体类型。但我不明白为什么它以前有效。

  1. 如果我创建一个新文件,这条线可以工作,假设这是一个 NSArray 的方法。为什么编译器在这种情况下不显示错误?

  2. 在显示错误消息时,显示了几种可能的计数方法接收器。(NSArray,NSDictionary,NSSet)它是否搜索所有可以接收该消息的类并在有多个时显示错误?

  3. 我注意到导入“-Swift.h”文件时发生错误。怎么看?

4

2 回答 2

6

编译器不会强制转换或检查您的id类型。它只是为您提供所有可能的选择器。你说这个问题与导入“-Swift.h”文件有关。在这种情况下,请检查您的 Swift 代码,可能您有count对 Objective C 可见的函数,它返回的不是Int.

此外,您可以在 中检查问题Issue navigator,选择它,它将显示count在 Objective C 中可见的所有调用。检查它们,其中大多数将返回 NSUInteger,但应该有一个返回其他内容,例如:

SWIFT_CLASS("_TtC3dev19YourClass")
@interface YourClass : NSObject
- (int32_t)count SWIFT_WARN_UNUSED_RESULT;
@end

于 2018-10-05T12:58:53.000 回答
5

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 中通常是一个坏主意,尤其是如果您在其上调用方法,则尤其是一个坏主意,因为编译器无法检查对象是否会响应并且您可能会崩溃。

于 2018-10-05T13:40:13.183 回答