“ id”类型如何理解方法的接收者而无需强制转换?

时间:2018-10-05 09:37:28

标签: ios objective-c swift objc-bridging-header

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

id test;
[test count];
  

找到多个名为“ count”的方法,但结果不匹配。

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

  1. 如果我创建一个新文件,则假设这是NSArray的方法,则此行有效。为什么在这种情况下编译器不显示错误?

  2. 虽然显示错误消息,但显示了count方法的几种可能的接收者。 (NSArray,NSDictionary,NSSet)是否搜索所有可以接收该消息的类,如果有多个,则显示错误?

  3. 我注意到导入“ -Swift.h”文件时发生错误。它如何依赖?

2 个答案:

答案 0 :(得分:5)

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

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

count

答案 1 :(得分:5)

Objective-C不需要知道接收器的类型。在运行时,所有对象都只是id,并且所有内容都是动态调度的。因此,无论消息的类型如何,任何消息都可以发送到任何对象。 (在运行时,对象可以自由决定如何处理他们不了解的消息。最常见的操作是引发异常和崩溃,但是有许多对象可以处理不了解的消息。 t直接映射到方法调用。)

但是,有几个技术细节使这变得复杂。

ABI(应用程序二进制接口)定义了用于返回某些原始类型的不同机制。只要该值是“字大小的整数”,就没有关系(这包括NSInteger和所有指针,也就是说,扩展了所有对象)。但是在某些处理器上,浮点数在返回的寄存器中与整数不同,而结构(如CGRect)则根据其大小而以各种方式返回。为了编写必要的汇编语言,编译器必须知道它将是哪种返回值。

ARC增加了一些额外的问题,要求编译器进一步了解参数的类型(特别是参数是对象还是基元),以及是否需要考虑任何内存管理属性。

只要编译器能够弄清楚test的类型和属性,它就不会真正在乎-count是什么类型。因此,在处理id值时,它会查看它可以看到的每个已知选择器(即,在包含的标头或当前.m中定义的每个选择器)。只要他们都同意,就可以在不同的班级中有很多人。但是,如果根本找不到选择器,或者某些接口不同意,那么它将无法编译代码行。

正如lobstah所指出的,您可能在Swift代码中的某个地方有一个类型为@objc的{​​{1}}方法或一个名为count()的{​​{1}}属性,该类型返回其他内容比@objc(映射到count,因此匹配Int的常规签名)。您需要修复该方法,或者将其从ObjC中隐藏(例如,通过添加NSInteger)。

或更妙的是:摆脱-count,并使用其实际类型。 @nonobjc在Cocoa中通常不是一个好主意,如果在其上调用方法,则尤其是个坏主意,因为编译器无法检查对象是否会响应并且您可能会崩溃。