Cómo corregir keyWindow obsoleto en iOS 13: guía completa

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

«keyWindow» está obsoleto. ¿Qué hacer?

\n\n

Si alguna vez has escrito:

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

…seguramente has visto la advertencia amarilla de Xcode: «'keyWindow' was deprecated in iOS 13.0». Esta es una de las preguntas más frecuentes en Stack Overflow (más de 100,000 visitas), y con razón: Apple realmente cambió las reglas del juego.

\n\n

En este artículo analizaremos por qué sucedió esto y compararemos 4 enfoques para obtener la ventana de la aplicación sin usar la API obsoleta. Aprenderás qué método es adecuado para UIKit, SwiftUI, SceneDelegate y cuándo usar cada uno. ¡Allá vamos!

\n\n

¿Por qué Apple eliminó keyWindow?

\n\n

Antes de iOS 13, la aplicación tenía una ventana principal — keyWindow. Todo era simple: la tomábamos y trabajábamos. Pero con la llegada de iPadOS y la multitarea (Split View, Slide Over), una aplicación puede tener varias ventanas simultáneamente. Cada ventana es gestionada por su propio UIWindowScene. El concepto de «ventana clave» se volvió difuso.

\n\n

Apple ahora recomienda obtener la ventana a través de la escena (UIWindowScene) a la que pertenece tu controlador o vista.

\n\n

Comparación de enfoques: de lo simple a lo correcto

\n\n

Veremos 4 formas, desde «silenciar rápidamente la advertencia» hasta «hacerlo como Apple». Elige la que se adapte a tu arquitectura.

\n\n

1. Solución rápida: UIApplication.shared.windows.first(where:)

\n\n

La respuesta más popular en Stack Overflow es usar la propiedad windows en lugar de keyWindow:

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

Ventajas:

\n
    \n
  • Mínimos cambios en el código
  • \n
  • Funciona en iOS 13+
  • \n
\n\n

Desventajas:

\n
    \n
  • Todavía no es seguro con múltiples ventanas
  • \n
  • Puede devolver nil si la ventana aún no se ha creado
  • \n
  • Apple aún lo marca como «obsoleto» en algunos contextos
  • \n
\n\n

Cuándo usarlo: Solo para prototipos rápidos o si tienes exactamente una ventana (por ejemplo, una aplicación de iPhone sin múltiples ventanas).

\n\n

2. A través de SceneDelegate: el camino correcto para UIKit

\n\n

A partir de iOS 13, Apple introdujo UISceneDelegate. En el método scene(_:willConnectTo:options:) recibes un UIWindowScene y puedes guardar una referencia a la ventana.

\n\n

Paso 1: En SceneDelegate.swift declara la propiedad 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

Paso 2: Obtén la ventana a través de la escena:

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

O, si necesitas la ventana principal en cualquier lugar de la aplicación, guarda una referencia al SceneDelegate y su window.

\n\n

Ventajas:

\n
    \n
  • Totalmente conforme con las recomendaciones de Apple
  • \n
  • Funciona correctamente con múltiples ventanas
  • \n
  • Seguro para la multitarea en iPad
  • \n
\n\n

Desventajas:

\n
    \n
  • Requiere configurar SceneDelegate (si aún no lo has hecho)
  • \n
  • Un poco más de código
  • \n
\n\n

3. A través de UIWindowScene.activeWindow (iOS 15+)

\n\n

A partir de iOS 15, UIWindowScene

Blogs

Book Recommendations