如何修复iOS 13中已弃用的keyWindow:完整指南

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

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

开始课程

「keyWindow」已弃用。该怎么办?

\n\n

如果你曾经写过:

\n\n
guard let window = UIApplication.shared.keyWindow else { return }
\n\n

……那么你肯定见过Xcode的黄色警告:「'keyWindow' was deprecated in iOS 13.0」。这是Stack Overflow上最常见的问题之一(超过10万次浏览),这并不奇怪——苹果确实改变了游戏规则。

\n\n

在本文中,我们将分析为什么会发生这种情况,并比较4种方法来获取应用程序窗口而不使用已弃用的API。你将了解哪种方法适用于UIKit、SwiftUI、SceneDelegate,以及何时使用每种方法。开始吧!

\n\n

为什么苹果弃用了keyWindow?

\n\n

在iOS 13之前,应用程序只有一个主窗口——keyWindow。一切都很简单:获取它然后使用。但随着iPadOS和多任务处理(分屏视图、侧拉)的到来,应用程序可能同时拥有多个窗口。每个窗口由其自己的UIWindowScene管理。「关键窗口」的概念变得模糊。

\n\n

苹果现在建议通过场景(UIWindowScene)来获取窗口,该场景属于你的控制器或视图。

\n\n

方法比较:从简单到正确

\n\n

我们将介绍4种方法,从「快速消除警告」到「按苹果的方式做」。选择适合你架构的方法。

\n\n

1. 快速修复:UIApplication.shared.windows.first(where:)

\n\n

Stack Overflow上最流行的答案是使用windows属性代替keyWindow:

\n\n
if let window = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) {\n    // 使用 window\n}
\n\n

优点:

\n
    \n
  • 代码改动最少
  • \n
  • 在iOS 13+上有效
  • \n
\n\n

缺点:

\n
    \n
  • 在多个窗口时仍然不安全
  • \n
  • 如果窗口尚未创建,可能返回nil
  • \n
  • 在某些上下文中,苹果仍将其标记为「已弃用」
  • \n
\n\n

何时使用:仅用于快速原型,或者如果你的应用确实只有一个窗口(例如,没有多窗口功能的iPhone应用)。

\n\n

2. 通过SceneDelegate:UIKit的正确方法

\n\n

从iOS 13开始,苹果引入了UISceneDelegate。在scene(_:willConnectTo:options:)方法中,你会获得UIWindowScene,并可以保存对窗口的引用。

\n\n

步骤1:在SceneDelegate.swift中声明window属性:

\n\n
class SceneDelegate: UIResponder, UIWindowSceneDelegate {\n\n    var window: UIWindow?\n\n    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {\n        guard let windowScene = (scene as? UIWindowScene) else { return }\n        window = UIWindow(windowScene: windowScene)\n        window?.rootViewController = ViewController()\n        window?.makeKeyAndVisible()\n    }\n}
\n\n

步骤2:通过场景获取窗口:

\n\n
if let windowScene = view.window?.windowScene,\n   let window = windowScene.windows.first {\n    // 使用 window\n}
\n\n

或者,如果你需要在应用程序的任何地方获取主窗口,可以保存对SceneDelegate及其window的引用。

\n\n

优点:

\n
    \n
  • 完全符合苹果的建议
  • \n
  • 正确处理多个窗口
  • \n
  • 在iPad上安全处理多任务
  • \n
\n\n

缺点:

\n
    \n
  • 需要配置SceneDelegate(如果你尚未迁移)
  • \n
  • 代码稍多
  • \n
\n\n

3. 通过UIWindowScene.activeWindow(iOS 15+)

\n\n

从iOS 15开始,UIWindowScene

博客

书籍推荐