在Swift 4模式下使用Swift 3的@objc推断已经被弃用了吗?

496
简而言之,使用Xcode 9 Beta时,我遇到了以下警告:
引用: “在Swift 4模式下使用Swift 3 @objc推断已被弃用。请处理已弃用的@ objc推断警告,使用“使用已弃用的Swift 3 @ objc推断”记录启用测试代码,并禁用Swift 3 @ objc推断。”
经过一番调查,我仍然不知道如何解决这个问题。非常感谢任何关于如何解决此问题以及对发生的事情的解释的提示。
我的目标是更好地理解我的代码正在发生什么。

4
我不太清楚警告信息是由哪个对象引起的。 Xcode没有明确指出该对象在哪一行。有什么建议可以找出这个警告来自哪里吗? - olyv
12个回答

821
通过将我的目标的“Swift 3 @objc 推断”构建设置更改为“默认”,我消除了这个警告。 参考在Xcode9中禁用Swift 3 @objc推断,从此文章中得知: 在Swift 4之前,编译器会自动将一些Swift声明提供给Objective-C。例如,如果从NSObject派生子类,则编译器会为这些类中的所有方法创建Objective-C入口点。该机制称为@ objc推断。 在Swift 4中,这种自动@ objc推断已被弃用,因为生成所有这些Objective-C入口点是昂贵的。当将“Swift 3 @objc Inference”设置为“On”时,它允许旧代码正常工作。但是,它将显示需要处理的弃用警告。建议“修复”这些警告并将设置切换为“默认”,这是新Swift项目的默认设置。请参阅此Swift提案以获取更多信息。

5
谢谢,Evgenii。这是一个长期解决方案吗? - DaleK
6
是的,我相信是这样的。根据我在回答中提到的Swift提案,objc推断被弃用了。设置"Swift 3 objc Inference"仅存在于从旧版本Swift迁移的项目中。如果创建一个新项目,则该设置不再存在,这意味着关闭了objc推断。建议解决任何objc推断警告并将其设置为“Off”。 - Evgenii
4
XCode中的信息提示建议说:“在Swift 4模式下使用Swift 3 @objc 推断已经被弃用。请解决所有弃用的@objc推断警告,测试您的代码并启用“使用已弃用的Swift 3 @objc 推断”的日志记录,并禁用Swift 3 @objc推断。”你知道在哪里启用所述的Swift 3 @objc 推断日志记录吗? - 0x416e746f6e
4
根据Swift提案,可以将SWIFT_DEBUG_IMPLICIT_OBJC_ENTRYPOINT环境变量设置为1到3的值,以在日志中查看Objective-C入口点的使用情况。 - Evgenii
14
只是补充一下 - 你需要对所有的构建目标进行这个操作,而不仅仅是项目。 - Krivvenz
显示剩余6条评论

272

- 什么是@objc推断?它是怎样工作的?

Swift 3中,编译器会在许多地方自动推断添加@objc,因此您不需要手动添加。换句话说,它会为您添加@objc

但在Swift 4中,编译器不再像以前那么自动推断添加了。现在您必须显式地添加@objc

默认情况下,在Swift 4之前的项目中,您会收到有关此事的警告。在Swift 4项目中,您将收到构建错误。这是通过SWIFT_SWIFT3_OBJC_INFERENCE构建设置来控制的。在Swift 4前的项目中,此设置为On。强烈建议将其设置为Default(或Off),这是新项目的默认选项。

转换所有内容需要一些时间,但由于它是Swift 4的默认设置,所以值得这样做。

- 如何停止编译器的警告/错误?

有两种方法可以转换您的代码,使编译器不再抱怨。

一种方法是在需要暴露给Objective-C运行时的每个函数或变量上使用@objc

@objc func foo() {

}

另一种方法是在 Class 声明中使用 @objcMembers。这将确保自动向类中的所有函数和变量添加 @objc。 这是一种简单的方法,但是它有一个代价,例如它可能通过暴露不需要暴露的函数来增加应用程序的大小。

@objcMembers class Test {

}

- 什么是 @objc,为什么需要它?

如果你在 Swift 类中引入了新的方法或变量,并将它们标记为 @objc,则会将它们暴露给 Objective-C 运行时。这在你的 Swift 类被 Objective-C 代码使用时非常必要,或者当你正在使用像 Selectors 这样的 Objective-C 特性时也是必须的。例如,目标-动作模式: button.addTarget(self, action:#selector(didPressButton), for:.touchUpInside)

- 为什么不把所有东西都标记为 @objc

将某些内容标记为 @objc 也有其负面影响:

  • 应用程序二进制文件增大
  • 无法进行函数重载

请记住,这只是一个非常简单的概述,实际情况比我写的更加复杂。我建议阅读实际的提案以获取更多信息。

参考来源:


1
@objc 不意味着动态分派,Swift 可以自由使用静态或虚拟分派(并可能因此执行不同的代码)。dynamic 关键字是强制 Swift 使用动态分派的必要条件。 - kevin
7
有其他方法可以为按钮添加动作吗?如果 @objc 被弃用了,我们应该使用什么? - Aznix
在一个混合了大量Objective-C和Swift的代码库中,迁移到Swift 4意味着需要添加数十个甚至数百个"@objc"。或者我做错了什么?目前似乎明智的做法是将这样的项目保留在Swift 3上。 - Stefan
5
@Stefan 是的,可能需要进行很多转换。将其分成几个阶段。将 SWIFT_SWIFT3_OBJC_INFERENCE 设置为“On”。首先转换为 Swift 4,然后处理 @objc 相关内容。为了简化操作,请遵循基本规则:如果 Swift 类在 Objc-C 代码中使用(通过桥接头文件),请使用 @objcMembers;否则,请逐个添加 @objc。可以使用 Xcode 搜索查找任何 .m 文件中是否调用了 Swift 类。这应该使转换相对轻松。 - kgaidis
5
@DaleK,这应该被接受为答案。抑制警告并使事情在Swift 3中正常工作是一种选择,但我认为不是最好的选择。重要的是要理解为什么 @objc 在Swift 4中发生了变化,然后再做出决定来修复项目并保持其原样。 - derpoliuk
2
感谢这个简短的解释。 - Schmoudi

49

迁移器无法识别所有需要@objc的函数
已标记为已弃用的推测Objective-C桥接方法可帮助您找到它们
• 构建关于已弃用方法的警告
• 运行已弃用桥接方法时的控制台消息

在此输入图片描述


1
那么我应该如何处理@objc?删除它?留下它?我已经将其删除了。但是我得到了这些警告,所以我需要添加它们吗? 在步骤3中,我应该如何处理那个? - Shial
在 func 前面加上 @objc。 - Hassan Taleb
1
第三步是关于什么的?您可以添加一些描述 :) - Shial
在我的情况下,我收到了这个警告,但没有指向任何代码。有两种方法被标记为@objc,它们似乎是唯一需要的方法。我将其更改为默认值,但仍然在编译期间收到警告。 - Maury Markowitz

12

我在使用“Swift 3 @objc 推断” = “默认”设置时遇到了这个警告。后来我意识到这是针对整个项目而不是目标设定的。因此,请确保您的目标中有“默认”设置以消除警告。


即使我在项目设置中更改为默认值,仍然花费了20分钟寻找解决错误的方法。你指出了需要在目标中进行更改的确切位置。 - SkrewEverything

8
你可以简单地传递“default”而不是“ON”。更符合苹果的逻辑。(但关于使用@obj的所有其他评论仍然有效。)

7

实际上,您可以通过禁用Swift 3 @objc推断来摆脱这些警告。 然而,可能会出现一些微妙的问题。例如,KVO将停止工作。 在Swift 3下,此代码完美运行:

for (key, value) in jsonDict {
    if self.value(forKey: key) != nil {
        self.setValue(value, forKey: key)
    }
}

在迁移到Swift 4并将“Swift 3 @objc Inference”设置为默认值后,我的项目的某些功能停止工作。我进行了一些调试和研究,找到了解决方法。根据我的最佳知识,以下是选项:
  • 启用“Swift 3 @objc Inference”(仅适用于从Swift 3迁移现有项目的情况)enter image description here
  • 将受影响的方法和属性标记为@objc enter image description here
  • 使用@objcMembers重新启用整个类的ObjC推断enter image description here
重新启用@objc推断会产生警告,但这是最快的解决方案。请注意,它仅适用于从早期Swift版本迁移的项目。其他两个选项更加繁琐,需要一些代码挖掘和广泛测试。
另请参见https://github.com/apple/swift-evolution/blob/master/proposals/0160-objc-inference.md

7
我是一名偶尔的iOS开发者(很快会变得更多),但我仍然无法像其他答案所指导的那样找到设置(因为我没有那个答案中显示的Keychain项),所以现在我找到了它,我想添加这个带有突出显示位置的快照,您需要单击并查找以下内容:
  1. 从左上角开始
  2. 选择项目文件夹图标
  3. 选择项目文件夹图标下方的主要项目名称。
  4. 在右侧选择构建设置。
  5. 在TARGETS下选择您的项目。
  6. 向下滚动(或在搜索文本框中搜索推断一词)

Finding the setting


7
您可以尝试执行“Pod update”和/或“flutter clean”。
我还在Xcode中进行了以下设置。
Objective-C接口设置如下: ObjectiveC interface setting

2
Swift 3 @objc推断在Swift 4模式下已弃用。请解决@objc推断警告,启用“使用已弃用的Swift 3 @objc推断”日志记录测试代码,然后通过将“XMLParsingURL”目标的“Swift 3 @objc推断”构建设置更改为“默认值”来禁用推断。
操作步骤如下:
  1. 第一步,进入Build Setting

  2. 在Build Setting中搜索Inference

  3. 更改swift 3 @objc Inference为Default

参考图片:enter image description here

0
Swift 4 模式下使用 Swift 3 的 @objc 推断已经被弃用了吗?建议使用函数调用 @objc。
func call(){

foo()

}

@objc func foo() {

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接