Swift 3 @objc 推断已弃用:Swift 4 中该如何处理

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

为什么 Swift 3 @objc 推断正在成为过去?

\n\n

如果你曾经将项目从 Swift 3 更新到 Swift 4,那么你很可能遇到过这个令人不安的编译器警告:

\n\n
The use of Swift 3 @objc inference in Swift 4 mode is deprecated. \nPlease address this deprecated @objc inference warning, \nor disable the warning by setting the "Swift 3 @objc Inference" \nbuild setting to "Default" for the "Swift 4" target.
\n\n

这条消息并非只是形式。它背后是语言哲学的一个重要变化。在 Swift 3 中,编译器自行决定哪些方法和属性需要对 Objective-C 可见。这很方便,但也带来了隐藏的问题:二进制体积增大,性能下降。Swift 4 决定终结这种“猜测”,并将控制权交还给开发者。

\n\n

在本文中,我们将探讨什么是 @objc 推断,为什么它被 弃用,如何修复该警告,以及在现代项目中应使用哪些最佳实践。我们开始吧!

\n\n

什么是 @objc 推断,它在 Swift 3 中是如何工作的?

\n\n

在 Swift 3 中,存在隐式的 @objc 转换。这意味着,如果一个类继承自 NSObject 或使用了 @objc 协议,编译器会自动使其所有方法对 Objective-C 可见。这种机制被称为 @objc 推断(隐式推断)。

\n\n

Swift 3 中的示例:

\n\n
class MyViewController: UIViewController {\n    func buttonTapped() {\n        print("Button tapped")\n    }\n}
\n\n

在 Swift 3 中,方法 buttonTapped() 会自动变为 @objc。你可以将其传递给 #selector,或将其用作 UIControl 的 target。方便吗?是的。但代价是二进制文件的不必要膨胀和优化机会的丧失。

\n\n

为什么 Apple 决定放弃自动推断?

\n\n

原因有几个,都关乎效率和可控性:

\n\n
    \n
  • 应用程序大小。 每个标记为 @objc 的方法都会为 Objective-C 运行时生成额外的包装代码。在大型项目中,这可能会增加数兆字节的多余代码。
  • \n
  • 性能。 Swift 是一种具有静态类型和强大优化能力的语言。一旦方法变为 @objc,编译器就会失去应用一系列优化的能力(例如内联)。
  • \n
  • 明确性。 Swift 4 走上了明确性的路线。开发者应自行决定哪些内容应对 Objective-C 可见。这简化了代码理解,并减少了意外错误。
  • \n
  • Swift 的未来。 Apple 正在逐步摆脱对 Objective-C 的依赖。隐式桥接越少,Swift 就能越快成为完全独立的语言。
  • \n
\n\n

警告在实践中是什么样子的?

\n\n

假设你有一个用 Swift 3 编写的项目。你将 "Swift Language Version" 设置切换为 Swift 4.0,然后收到数十个(甚至数百个)这样的警告:

\n\n
class LegacyViewController: UIViewController {\n    // 警告:在 Swift 4 模式下使用 Swift 3 @objc 推断已弃用\n    func legacyAction() {\n        // ...\n    }\n\n    @objc func explicitAction() {\n        // 此方法已标记 @objc — 一切正常\n    }\n}
\n\n

编译器对 legacyAction() 报错,因为它没有标记 @objc,但以前编译器会自动执行此操作。现在需要解决方案。

\n\n

修复警告的三种方法

\n\n

你有三种选择。选择最适合你项目的那一种:

博客

书籍推荐