wandres.dev
UIKIT · lo que sigue vivo

Por qué UIKit en 2026: herencia, cobertura y sustrato

La pregunta no es sentimental sino técnica: por qué estudiar un framework que Apple presenta como el capítulo anterior. Esta lección desarma la duda en tres argumentos independientes —el volumen de código heredado que sostiene la industria, las zonas del sistema que SwiftUI todavía no cubre, y el hecho de que en iOS SwiftUI no sustituye a UIKit sino que se apoya en él— y termina proponiendo un plan de estudio proporcionado al trabajo real de alguien que programa en declarativo.

⏱ 17 min

Hay una pregunta que todo desarrollador formado en SwiftUI acaba formulándose, casi siempre el día en que abre un proyecto ajeno y encuentra archivos que no reconoce. Por qué habría de estudiar un framework que la propia Apple presenta como el capítulo anterior. La respuesta honesta no apela a la nostalgia ni a la compatibilidad hacia atrás: apela a tres hechos independientes que se refuerzan entre sí. El primero es demográfico, y consiste en que la mayor parte del código iOS que hoy genera ingresos es anterior a 2019. El segundo es funcional, y consiste en que quedan regiones del sistema donde el modelo declarativo aún delega o directamente no llega. El tercero es el decisivo y el peor entendido: en iOS, SwiftUI no reemplaza a UIKit, se apoya en él. Cada vez que la abstracción se agrieta —y se agrieta— lo que asoma por debajo es un UIViewController, una CALayer y una cadena de respondedores. Estudiar UIKit en 2026 no es estudiar el pasado; es estudiar el suelo sobre el que se levanta lo que ya sabes.

🎯 Al terminar esta lección sabrás
  • Distinguir los tres argumentos independientes que justifican estudiar UIKit hoy y decidir cuáles te aplican.
  • Situar SwiftUI dentro de la pila real de iOS y saber qué existe por debajo de cada vista declarativa.
  • Identificar las zonas del sistema donde SwiftUI todavía delega en UIKit o carece de equivalente.
  • Diseñar un plan de estudio proporcionado, que no se convierta en un segundo curso completo.

La abstracción tiene fondo

La ley de las abstracciones con fugas, formulada por Joel Spolsky hace más de dos décadas, dice que toda abstracción no trivial acaba filtrando detalles de lo que oculta. SwiftUI es una abstracción excelente y no es una excepción. En macOS se apoya en AppKit, en iOS se apoya en UIKit, y esa dependencia no es un detalle de implementación irrelevante: es visible desde el primer minuto en que algo va mal.

El punto exacto de contacto tiene nombre y es fácil de ver. Toda app de SwiftUI en iOS, incluida la que usa el ciclo de vida moderno con App y WindowGroup, termina alojada dentro de un controlador de UIKit. Cuando escribes una escena declarativa el sistema construye por ti lo que en un proyecto mixto escribirías a mano.

// Lo que el ciclo de vida de SwiftUI construye por debajo
let raiz = UIHostingController(rootView: ContenidoView())
window.rootViewController = raiz
window.makeKeyAndVisible()

Esa frontera explica fenómenos que de otro modo parecen caprichos del framework. El teclado que empuja el contenido lo hace porque hay un UIScrollView real ajustando sus insets. La barra de navegación que ignora un modificador lo ignora porque quien manda es un UINavigationController con su propia noción de apariencia. El gesto que deja de funcionar al añadir un contenedor lo hace porque hay un reconocedor de gestos compitiendo en una jerarquía que no escribiste. Y el depurador de vistas de Xcode, cuando abres una app de SwiftUI, no te muestra tus estructuras: te muestra un árbol de vistas de UIKit con nombres internos, porque ese árbol es lo que realmente existe en memoria.

flowchart TB
a[Tus vistas declarativas en SwiftUI] --> b[Motor de reconciliacion y AttributeGraph]
b --> c[UIHostingController y vistas host de UIKit]
c --> d[UIView y la cadena de respondedores]
d --> e[CALayer y Core Animation]
e --> f[Compositor del sistema y GPU]

Hay una forma barata de comprobar todo esto en treinta segundos y merece la pena hacerla antes de seguir leyendo, porque el efecto de verlo con los propios ojos es mayor que el de aceptarlo por escrito. Basta con imprimir la descripción recursiva de la ventana desde una pausa del depurador.

// Desde el depurador, sobre una app de SwiftUI en ejecucion
// po UIApplication.shared.connectedScenes
// po window.rootViewController
// po window.recursiveDescription()

Lo que aparece no son tus estructuras declarativas sino una jerarquía de vistas de UIKit con nombres internos, hospedada bajo un controlador anfitrión, con sus marcos calculados, sus capas y sus áreas seguras. Ese árbol es lo que el compositor del sistema recibe; tus tipos declarativos son la receta que lo produjo y que ya no existe como tal en tiempo de ejecución.

El mismo razonamiento se aplica al eje temporal. Toda actualización de interfaz en iOS ocurre dentro de un ciclo del bucle de ejecución y se materializa en una transacción de Core Animation que se confirma al final del ciclo. Cuando una animación de SwiftUI se comporta de forma inesperada al combinarse con un cambio provocado desde fuera, la explicación casi siempre vive en ese nivel: dos cambios que caen en transacciones distintas, o uno que cae dentro de una transacción implícita que alguien abrió sin saberlo.

Conviene precisar hasta dónde llega la analogía, porque la comparación con el navegador web es tentadora y engañosa. SwiftUI no dibuja sobre un lienzo propio ignorando a UIKit; cada contenedor relevante —una lista, una pila de navegación, un campo de texto— tiene detrás una vista de UIKit con su ciclo de vida completo. El motor declarativo decide qué debe existir y con qué valores; la maquinaria imperativa decide cómo se materializa, se mide, se dibuja y se compone. Quien solo conoce la mitad de arriba puede construir apps excelentes, pero se queda sin vocabulario justo en el momento en que la mitad de abajo se manifiesta.

ℹ️
Una asimetría útil de recordar

Aprender UIKit después de SwiftUI es mucho más fácil que el camino inverso, y el motivo es que ya traes el modelo mental de estado y composición. Lo que te falta no es una filosofía nueva, es un vocabulario de objetos concretos: quién posee la vista, quién la mide, quién recibe el toque, quién sobrevive a la rotación. Ese vocabulario se adquiere en semanas, no en meses.

El argumento demográfico

El segundo argumento es el más prosaico y el que decide más contrataciones. UIKit se presentó en 2008 y SwiftUI en 2019; hay once años de acumulación por un lado y una adopción gradual por el otro. Ninguna cifra pública es fiable al detalle, pero cualquiera que haya abierto proyectos ajenos reconoce el patrón: las aplicaciones grandes y rentables casi nunca son proyectos nuevos, y las que sí incorporan SwiftUI lo hacen por adición, pantalla a pantalla, sobre una base imperativa que sigue viva.

🧱

Base heredada

Apps de banca, comercio, salud y logística escritas entre 2012 y 2019. Funcionan, facturan y nadie va a reescribirlas. El trabajo consiste en añadir pantallas nuevas sin romper las viejas.

🔀

Codigo mixto

El caso más común de todos. Navegación en UIKit, pantallas nuevas en SwiftUI y una frontera de adaptadores en medio. Exige entender los dos lados a la vez.

🌱

Proyecto nuevo

Enteramente declarativo hasta que aparece el primer requisito que no encaja. Entonces se abre un hueco de interoperabilidad y hay que saber qué poner dentro.

Hay una consecuencia profesional que conviene decir sin rodeos. Un desarrollador que solo sabe SwiftUI puede trabajar sin problemas en el tercer escenario y con dificultad en el segundo, pero queda excluido del primero, que es donde está la mayor parte del presupuesto. La asimetría no se debe a que UIKit sea mejor, sino a que el software que gana dinero envejece y nadie lo reescribe por gusto. Quien entiende ambos mundos no compite por las mismas plazas.

El argumento tiene además una versión arqueológica que va más allá del empleo. Leer código de UIKit escrito por buenos equipos enseña cosas que el estilo declarativo esconde: cómo se gestiona la propiedad de los objetos, dónde se cancela el trabajo pendiente, cómo se sincroniza una animación con la llegada de datos. Son problemas que SwiftUI resuelve por ti, y precisamente por eso resulta instructivo ver cómo se resolvían a mano.

Los huecos que quedan

El tercer argumento es funcional y hay que exponerlo con cuidado, porque la lista de carencias de SwiftUI se acorta cada año y repetir una desactualizada es la forma más rápida de perder credibilidad. La formulación correcta no es que SwiftUI sea incompleto, sino que existen dominios donde la superficie declarativa cubre el ochenta por ciento del caso y el veinte restante exige bajar.

El texto es el ejemplo canónico. Un TextField cubre la entrada normal con solvencia, pero en cuanto aparece un editor con atributos, resaltado de sintaxis, menciones que se comportan como una unidad o control fino del contenedor de texto, el camino pasa por UITextView y por la maquinaria de TextKit. Lo mismo ocurre con la cámara cuando se necesita una capa de previsualización personalizada, con la impresión, con la manipulación avanzada del portapapeles y con las interacciones de arrastrar y soltar que requieren sesiones y elementos tipados.

⚠️
Cómo envejecen mal las listas de carencias

Muchos huecos citados hace tres años ya no existen: el control programático de la posición de scroll, buena parte de la personalización de listas, las animaciones por fases o el acceso al foco del teclado tienen hoy API declarativa. Por eso la habilidad valiosa no es memorizar una lista, sino saber diagnosticar. La pregunta correcta ante un requisito extraño siempre es la misma: existe un modificador que lo exprese, y si no existe, qué objeto de UIKit lo controlaba antes.

Conviene además distinguir dos tipos de hueco que suelen mezclarse en la misma conversación. Está el hueco de cobertura, donde no existe API declarativa y hay que envolver, y está el hueco de control, donde sí existe API pero no expone la palanca que necesitas: una animación que no puedes interrumpir a mitad, una celda que no puedes reconfigurar sin recrear, un desplazamiento cuya desaceleración no puedes ajustar. El segundo es más frecuente que el primero y también más frustrante, porque el código funciona y sencillamente no hace lo que necesitas.

Existe todavía un tercer hueco, más silencioso, que aparece cuando el requisito no es una función sino un número. Una pantalla que debe mantener ciento veinte cuadros por segundo con miles de elementos, o un arranque que debe caer por debajo de un umbral contractual, imponen un presupuesto de trabajo por cuadro. Cumplirlo exige a veces controlar la reutilización, la carga anticipada o el momento exacto en que se descodifica una imagen, y ese control se ejerce en el nivel imperativo porque es donde están las palancas.

// El envoltorio: donde se paga el conocimiento de UIKit
struct EditorRico: UIViewRepresentable {
    @Binding var texto: NSAttributedString

    func makeUIView(context: Context) -> UITextView {
        let vista = UITextView()
        vista.delegate = context.coordinator
        return vista
    }

    func updateUIView(_ vista: UITextView, context: Context) {
        guard vista.attributedText != texto else { return }
        vista.attributedText = texto
    }

    func makeCoordinator() -> Coordinador { Coordinador(self) }
}

Ese fragmento parece trivial y esconde cuatro decisiones que solo se toman bien conociendo el framework de abajo: quién posee la vista, por qué la comparación previa a asignar evita un bucle infinito de actualizaciones, por qué el coordinador debe existir para no perder el delegado, y qué ocurre con el tamaño si la vista envuelta no declara el suyo.

La salida de emergencia es una sola y está estandarizada: UIViewRepresentable y UIViewControllerRepresentable para traer piezas imperativas al mundo declarativo, y UIHostingController para el viaje contrario. Esa es la razón práctica más fuerte de todas. Para escribir un adaptador correcto necesitas saber cuándo se llama al método de creación, cuándo al de actualización, quién posee el objeto envuelto, cómo se propaga el tamaño y cómo se evita el ciclo de retención con el coordinador. Nada de eso se puede escribir a ciegas: exige el modelo mental de UIKit, aunque solo lo uses veinte líneas al año.

Cuánto estudiar y en qué orden

Queda la parte más importante y la que casi nadie plantea: la dosis. UIKit es enorme y aprenderlo entero en 2026 sería una mala inversión, del mismo modo que sería absurdo estudiar hoy la totalidad de una biblioteca cuyo mantenimiento está en modo estable. La estrategia que rinde consiste en tratarlo como se trata un idioma para leer: pasiva en casi todo, activa en un núcleo pequeño.

Ese núcleo tiene cuatro piezas y ocupará las cuatro lecciones siguientes. El ciclo de vida del controlador, porque es el objeto que estructura toda app imperativa y porque explica el modelo de propiedad. Auto Layout, porque es el motor de restricciones que sigue midiendo mucho de lo que ves y porque ilumina por contraste el algoritmo de SwiftUI. UICollectionView moderno, porque su diseño con layout composicional y fuente de datos diferenciable es una de las mejores APIs que Apple ha publicado y sigue siendo la referencia en colecciones complejas. Y el criterio de recorte, que es saber qué ignorar sin culpa.

Aprender el sustrato es lo que separa a quien usa un framework de quien lo entiende

Existe un patrón que se repite en toda la historia del software y que conviene nombrar, porque explica por qué esta lección no trata realmente de UIKit. Cada generación de herramientas construye una abstracción sobre la anterior y promete que el nivel inferior ya no importa. El compilador prometió que el ensamblador ya no importaba, el recolector de basura prometió que la gestión de memoria ya no importaba, el ORM prometió que el SQL ya no importaba, el navegador prometió que el sistema operativo ya no importaba. En todos los casos la promesa resultó ser cierta el noventa por ciento del tiempo y catastróficamente falsa el diez restante, y ese diez por ciento es exactamente donde se concentra la dificultad, el rendimiento y los bugs que nadie sabe explicar. La consecuencia no es que haya que aprenderlo todo hacia abajo hasta el silicio, porque eso es imposible y además improductivo. La consecuencia es más fina: hay que conocer un nivel por debajo de aquel en el que trabajas. Ni dos ni ninguno. Quien programa SwiftUI y conoce UIKit puede leer un depurador de vistas, entender por qué una lista se traba, escribir un adaptador correcto y decidir con criterio cuándo bajar. Quien solo conoce SwiftUI atribuye a la magia o a un fallo del framework fenómenos que tienen una causa mecánica perfectamente comprensible, y cada uno de esos episodios se resuelve por prueba y error en lugar de por deducción. La diferencia entre ambos perfiles no se nota en el trabajo cotidiano, donde la abstracción se sostiene; se nota entera el día que se rompe, y ese día llega siempre.

📝
Lo esencial

Tres razones independientes y ninguna nostálgica. La demográfica: casi todo el código iOS rentable es anterior a SwiftUI y crece por adición, no por reescritura. La funcional: quedan dominios —texto rico, cámara personalizada, impresión, interacciones complejas— donde el camino pasa por envolver una pieza imperativa, y escribir ese envoltorio exige el modelo mental de UIKit. Y la estructural, que es la definitiva: en iOS SwiftUI se materializa sobre UIViewController, UIView y CALayer, de modo que conocer ese nivel es lo que convierte los fenómenos inexplicables en mecánica observable. La dosis correcta es un núcleo pequeño y activo, no el framework entero.

⚔️ Ver el sustrato con tus propios ojos
  1. Abre una app tuya de SwiftUI, lánzala y captura la jerarquía con el depurador de vistas de Xcode; identifica el controlador anfitrión y cuenta cuántas vistas de UIKit hay por cada vista tuya.
  2. Coloca un punto de interrupción simbólico en un método de ciclo de vida de UIViewController y observa la pila de llamadas cuando presentas una hoja modal desde SwiftUI.
  3. Recorre los requisitos de tu app y clasifica cada pantalla en cubierta por SwiftUI, cubierta con esfuerzo, o necesitada de una pieza imperativa; justifica cada caso de la tercera categoría.
  4. Busca en una oferta de empleo real de iOS qué proporción de requisitos menciona UIKit y contrasta el resultado con tu propio plan de estudio.
  5. Escribe en media página qué nivel está justo por debajo del tuyo en las otras tecnologías que usas, y decide si lo conoces lo suficiente.