«keyWindow» is deprecated. What to do?
\n\nIf you've ever written:
\n\nguard let window = UIApplication.shared.keyWindow else { return }\n\n…then you've probably seen the yellow Xcode warning: «'keyWindow' was deprecated in iOS 13.0». This is one of the most common questions on Stack Overflow (over 100,000 views), and for good reason — Apple really changed the rules of the game.
\n\nIn this article, we'll break down why this happened and compare 4 approaches to get the app window without deprecated API. You'll learn which method is suitable for UIKit, SwiftUI, SceneDelegate, and when to use each one. Let's go!
\n\nWhy did Apple deprecate keyWindow?
\n\nBefore iOS 13, an app had one main window — keyWindow. Everything was simple: grab it and use it. But with the arrival of iPadOS and multitasking (Split View, Slide Over), an app can have multiple windows simultaneously. Each window is managed by its own UIWindowScene. The concept of a «key window» became blurred.
Apple now recommends getting the window through the scene (UIWindowScene) to which your controller or view belongs.
\n\nComparison of approaches: from simple to correct
\n\nWe'll look at 4 methods, from «quickly silence the warning» to «doing it the Apple way». Choose the one that fits your architecture.
\n\n1. Quick fix: UIApplication.shared.windows.first(where:)
\n\nThe most popular answer on Stack Overflow is to use the windows property instead of keyWindow:
if let window = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) {\n // use window\n}\n\nPros:
\n- \n
- Minimal code changes \n
- Works on iOS 13+ \n
Cons:
\n- \n
- Still unsafe with multiple windows \n
- May return nil if the window hasn't been created yet \n
- Apple still marks this as «deprecated» in some contexts \n
When to use: Only for a quick prototype or if you definitely have one window (e.g., an iPhone app without multi-windowing).
\n\n2. Via SceneDelegate: the correct way for UIKit
\n\nStarting with iOS 13, Apple introduced UISceneDelegate. In the scene(_:willConnectTo:options:) method, you receive a UIWindowScene and can save a reference to the window.
Step 1: In SceneDelegate.swift, declare the window property:
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\nStep 2: Get the window through the scene:
\n\nif let windowScene = view.window?.windowScene,\n let window = windowScene.windows.first {\n // use window\n}\n\nOr, if you need the main window anywhere in the app, store a reference to the SceneDelegate and its window.
Pros:
\n- \n
- Fully complies with Apple's recommendations \n
- Works correctly with multiple windows \n
- Safe for multitasking on iPad \n
Cons:
\n- \n
- Requires setting up SceneDelegate (if you haven't migrated yet) \n
- Slightly more code \n
3. Via UIWindowScene.activeWindow (iOS 15+)
\n\nStarting with iOS 15, UIWindowScene
Blogs
Book Recommendations
Read also
JS Team: How Code Style Saves Nerves and Deadlines
Dependency Injection in PHP: A Complete Guide with Code Examples
Working with Task Queues in Kotlin: In Practice
WebAssembly and PHP: What Is It and Why? An Unexpected Tandem for the Web
Inserting an Element into a PHP Array at Any Position: Magic Under the Hood