Enfrentarse a una entrevista técnica como iOS Developer puede ser un desafío monumental, especialmente cuando el ecosistema de Apple evoluciona a un ritmo vertiginoso. La transición de UIKit al paradigma declarativo ha cambiado las reglas del juego. Hoy en día, las preguntas de entrevista para un iOS Senior Developer en SwiftUI no se limitan a saber cómo centrar un texto; evalúan tu profundo entendimiento de la programación Swift, la gestión de memoria, la concurrencia y la escalabilidad del código.
Como desarrollador senior, se espera que domines SwiftUI no solo en iPhone, sino que puedas extrapolar ese conocimiento para construir aplicaciones universales en iOS, macOS y watchOS utilizando Xcode.
En este artículo, hemos recopilado y respondido 100 preguntas clave que abarcan desde las entrañas de Swift hasta patrones de arquitectura avanzados. Úsalas como un checklist para validar tus conocimientos y brillar en tu próxima entrevista técnica.
I. Fundamentos de la Programación Swift
1. ¿Cuál es la diferencia técnica entre some View y any View en Swift? some View es un tipo opaco resuelto en tiempo de compilación (Static Dispatch), lo que permite optimizaciones. any View es un tipo existencial resuelto en tiempo de ejecución (Dynamic Dispatch), lo que implica un impacto en el rendimiento.
2. ¿Cómo funciona internamente el Static Dispatch frente al Dynamic Dispatch? El Static Dispatch permite al compilador saber exactamente qué bloque de código ejecutar, optimizándolo (ej. inlining). El Dynamic Dispatch utiliza la Witness Table (o Virtual Table en clases) para resolver el método en tiempo de ejecución.
3. ¿Qué es un Property Wrapper y cómo se implementa? Es una estructura que encapsula la lógica de lectura y escritura de una propiedad. Se implementa usando el atributo @propertyWrapper y requiere definir una propiedad wrappedValue.
4. ¿Cómo previenes Retain Cycles en closures dentro de SwiftUI? Utilizando listas de captura ([weak self] o [unowned self]) cuando el closure retiene a una clase (como un ViewModel) que a su vez retiene el closure.
5. ¿Cuál es la diferencia entre @escaping y @nonescaping en closures? Un closure @nonescaping (por defecto) se ejecuta y destruye antes de que la función retorne. Un closure @escaping sobrevive a la función, almacenándose en memoria para ejecutarse más tarde (común en llamadas asíncronas).
6. Explica qué es el Result Builder en Swift. Es una característica sintáctica que permite construir valores estructurados paso a paso, como listas o árboles. Es la magia detrás del ViewBuilder en SwiftUI.
7. ¿Qué diferencias existen entre Opaque Types y Generics? Los genéricos permiten al llamador decidir el tipo (func make<T>() -> T), mientras que los tipos opacos permiten a la función decidir el tipo ocultando los detalles al llamador (func make() -> some View).
8. ¿Cómo maneja Swift el Type Erasure? Se logra envolviendo un protocolo con Self o associatedtype en una clase/struct genérica (ej. AnyView, AnyPublisher), o usando la palabra clave any en Swift 5.6+.
9. ¿Qué es la directiva @dynamicMemberLookup? Permite a un tipo proveer acceso a propiedades utilizando sintaxis de punto (dot-notation) en tiempo de ejecución, muy utilizado en Bindings de SwiftUI.
10. ¿Cuál es la diferencia entre un Sequence y un Collection en Swift? Una Sequence puede ser iterada (posiblemente una sola vez y de forma destructiva), mientras que una Collection es una secuencia que garantiza acceso no destructivo y acceso directo a elementos mediante índices.
11. ¿Cuándo usarías unowned en lugar de weak? Usas unowned cuando tienes la certeza absoluta de que la referencia no será nil cuando se acceda a ella, evitando el desempaquetado de opcionales.
12. Explica el concepto de Copy-on-Write (CoW). Es una optimización en tipos por valor (como Array o String en Swift) donde los datos solo se copian en memoria si sufren una mutación.
13. ¿Qué es el protocolo Hashable y por qué es crucial en SwiftUI? Permite que un tipo produzca un valor entero (hash). Es vital en SwiftUI para iterar colecciones con ForEach o usar componentes como NavigationPath.
14. ¿Cómo funcionan las Associated Types en protocolos? Actúan como comodines para tipos que se definirán cuando un tipo concreto adopte el protocolo, permitiendo crear protocolos genéricos.
15. ¿Qué significa que Swift sea un lenguaje Protocol-Oriented? Significa que favorece la composición mediante protocolos y extensiones de protocolos en lugar de depender exclusivamente de la herencia de clases (OOP).
II. Gestión de Estado y Ciclo de Vida en SwiftUI
16. ¿Cuándo debes usar @StateObject frente a @ObservedObject? @StateObject se usa para instanciar y ser dueño del ciclo de vida del objeto. @ObservedObject se usa cuando la vista recibe un objeto cuyo ciclo de vida es gestionado por un padre.
17. Explica cómo @EnvironmentObject inyecta dependencias. Permite inyectar un ObservableObject en el entorno global de la jerarquía de vistas, haciéndolo accesible a cualquier vista descendiente sin pasarlo explícitamente.
18. ¿Qué problema resuelve @Binding? Permite a una vista hija leer y escribir un valor propiedad de una vista padre, manteniendo una única fuente de verdad (Single Source of Truth).
19. ¿Por qué es un anti-patrón inicializar un @ObservedObject directamente en una vista? Porque las vistas en SwiftUI son efímeras y se recrean constantemente. Al recrearse, el @ObservedObject perderá su estado anterior y se reinicializará, causando bugs de datos.
20. ¿Qué diferencia hay entre onAppear y task? onAppear ejecuta código síncrono cuando la vista aparece. task crea un contexto asíncrono y su ciclo de vida está atado al de la vista (se cancela automáticamente si la vista desaparece).
21. ¿Para qué se utiliza PreferenceKey en SwiftUI? Para pasar datos hacia arriba en la jerarquía de vistas (de hijo a padre), resolviendo el flujo unidireccional estándar que va de padre a hijo.
22. Explica la macro @Observable introducida en iOS 17. Reemplaza a ObservableObject, eliminando la necesidad de @Published. Optimiza el renderizado de vistas al rastrear automáticamente qué propiedades específicas se leen en una vista.
23. ¿Cómo forzarías el redibujado explícito de una vista específica? Cambiando el valor asociado al modificador .id(). Esto le dice a SwiftUI que destruya la vista anterior y cree una completamente nueva.
24. ¿Qué es el Environment (no EnvironmentObject)? Es un repositorio de valores predefinidos del sistema (como el esquema de color, tamaño de fuente, zona horaria) accesibles mediante el wrapper @Environment.
25. ¿Cómo implementas un estado persistente local en SwiftUI? Usando @AppStorage para guardar datos ligeros en UserDefaults, o @SceneStorage para mantener el estado de una pantalla/pestaña específica mientras la app está viva.
26. ¿Qué ocurre si actualizas un @State desde un hilo en segundo plano? En versiones antiguas causaba un crash. En SwiftUI moderno con Swift 5.5+, a menudo se redirige, pero la práctica correcta es actualizar la UI siempre desde el MainActor.
27. ¿Cómo se comunican dos vistas hermanas en SwiftUI? Elevando el estado (Lifting State) a un padre común y pasándolo a ambas como @Binding, o usando un ObservableObject inyectado en el padre.
28. ¿Qué es @FocusState y en qué plataformas brilla? Permite programar y leer qué elemento de la UI tiene el foco del teclado. Es crítico en iOS, macOS (navegación por teclado) y tvOS.
29. ¿Cuándo usarías @FetchRequest o @Query? Para integrar bases de datos locales directamente en la vista. @FetchRequest para CoreData y @Query para SwiftData (introducido en iOS 17).
30. ¿Qué hace objectWillChange.send()? Es un método de ObservableObject que emite un aviso al framework de que las propiedades del objeto van a cambiar, forzando un redibujado. Suele ejecutarse automáticamente con @Published.
III. Layout, Renderizado y Animaciones en SwiftUI
31. ¿Por qué se dice que GeometryReader rompe el layout declarativo? Porque toma todo el espacio disponible y fuerza a sus vistas hijas a depender de coordenadas absolutas, haciendo el código rígido y propenso a errores de redimensionamiento.
32. ¿Cómo funciona el nuevo protocolo Layout (iOS 16+)? Permite crear contenedores personalizados (como HStack o VStack a medida) definiendo reglas precisas de medición y posicionamiento sin usar GeometryReader.
33. ¿Cuál es el proceso de negociación de tamaño en SwiftUI?
- El padre ofrece un tamaño. 2. El hijo determina su propio tamaño. 3. El hijo devuelve su tamaño al padre. 4. El padre alinea al hijo en su espacio.
34. Explica la diferencia entre .frame(width:height:) y .frame(maxWidth:maxHeight:). El primero fuerza un tamaño estricto invariable. El segundo define límites elásticos, permitiendo que la vista se adapte dinámicamente al espacio disponible.
35. ¿Qué es matchedGeometryEffect? Un modificador que sincroniza las animaciones de dos vistas distintas simulando que son el mismo elemento moviéndose o transformándose a través de la pantalla.
36. ¿Cómo evitas que AnyView impacte en el rendimiento? Evitándolo por completo. Se debe usar @ViewBuilder en su lugar o agrupar vistas condicionales dentro de Group para no destruir la identidad estática de la jerarquía.
37. ¿Para qué sirve el modificador .equatable()? Permite evitar redibujados innecesarios en vistas complejas comparando si los nuevos datos son iguales a los anteriores (requiere que la vista conforme Equatable).
38. ¿Qué diferencia hay entre withAnimation y una animación implícita (.animation(...))? withAnimation (explícita) anima todos los cambios de estado dentro de su closure. .animation (implícita) se acopla a un valor específico y se dispara solo cuando ese valor cambia.
39. ¿Qué es el Canvas en SwiftUI? Un entorno de renderizado 2D de alto rendimiento. Es ideal para dibujar partículas, gráficos complejos o juegos simples donde dibujar millones de vistas afectaría el rendimiento.
40. ¿Cómo manejas las Safe Areas? SwiftUI las respeta por defecto. Para ignorarlas (ej. para un fondo completo), se usa el modificador .ignoresSafeArea().
41. ¿Qué es el Layout Priority? Un modificador (.layoutPriority()) que le dice al padre qué vista hija debe tener prioridad para reclamar espacio cuando el espacio total es insuficiente.
42. Explica qué es un ViewModifier personalizado. Es una estructura que adopta el protocolo ViewModifier para encapsular múltiples modificadores de estilo y comportamiento, permitiendo la reutilización limpia del código.
43. ¿Cómo funciona el enrutamiento con NavigationStack? A diferencia del antiguo NavigationView, NavigationStackmaneja la navegación basándose en datos, permitiendo pasar un array a path: y empujar vistas de manera programática.
44. ¿Qué es un Grid en SwiftUI (iOS 16+)? Un contenedor que alinea sus hijos bidimensionalmente en filas y columnas estructuradas, superior a anidar múltiples HStacks y VStacks.
45. ¿Cómo estilizas un texto con partes dinámicas en SwiftUI? Usando interpolación de AttributedString o concatenando elementos Text usando el operador +.
IV. Arquitectura y Patrones de Diseño
46. ¿Es MVVM el patrón definitivo para SwiftUI? No necesariamente. Aunque es popular, la arquitectura de SwiftUI ya actúa como un sistema de Data Binding nativo. A nivel senior, arquitecturas como TCA (The Composable Architecture) o Redux ganan mucha tracción.
47. Describe los principios de The Composable Architecture (TCA). Se basa en Estados, Acciones, Reducers y Entornos (Dependencias). Es unidireccional, predecible, altamente testeable y perfecto para aplicaciones complejas en programación Swift.
48. ¿Cómo implementas la Inyección de Dependencias en SwiftUI? A través del inicializador (constructor injection), usando Environment, o aplicando contenedores de dependencias con Property Wrappers personalizados.
49. ¿Por qué evitarías los Singletons en el desarrollo moderno de iOS? Hacen que el código sea rígido, ocultan las dependencias de una clase, dificultan las pruebas unitarias (testing) y pueden causar problemas de concurrencia.
50. ¿Qué es el patrón Coordinator o Router en SwiftUI? Un patrón extraído de UIKit para sacar la lógica de navegación fuera de la Vista, usando objetos que gestionan rutas (NavigationPath) inyectados como @EnvironmentObject.
51. Explica el principio SOLID: Inversión de Dependencias (DIP). Los módulos de alto nivel no deben depender de los de bajo nivel; ambos deben depender de abstracciones (Protocolos en Swift).
52. ¿Cómo desacoplas una vista SwiftUI de su modelo de negocio? Creando protocolos para el ViewModel (usando genéricos o tipos existenciales si usas iOS 16+) para que la vista solo conozca la interfaz de los datos, facilitando el mockeo.
53. ¿Qué es el State-Driven Routing? Es el enfoque de SwiftUI donde la navegación no se ejecuta imperativamente (ej. pushViewController), sino que la UI reacciona a los cambios en variables de estado (isPresented, path).
54. ¿Cuándo usarías el patrón Factory en una app SwiftUI? Para encapsular la compleja lógica de creación de vistas. Por ejemplo, un ViewFactory que retorna diferentes vistas basadas en el tipo de usuario o configuración.
55. Explica las diferencias entre Clean Architecture y VIPER. Ambos buscan separación de responsabilidades. VIPER es altamente granular (View, Interactor, Presenter, Entity, Router), mientras que Clean Architecture se enfoca en capas circulares (Dominio en el centro, Datos/UI afuera).
V. Concurrencia, Async/Await y Combine
56. ¿Qué problema resuelve async/await frente a los callbacks? Elimina el Callback Hell (pirámide de la perdición), hace el código lineal y manejable, y previene errores donde te olvidas de llamar al bloque de finalización.
57. ¿Qué es un Actor en Swift? Es un tipo por referencia que aísla su estado mutando datos de manera serial, protegiendo contra condiciones de carrera (Data Races) en entornos concurrentes.
58. Explica el atributo @MainActor. Asegura que todas las propiedades o funciones marcadas se ejecuten exclusivamente en el hilo principal, crítico para actualizaciones de UI en SwiftUI.
59. ¿Cuál es la diferencia entre Task y Task.detached? Task hereda el contexto de ejecución (como el @MainActor o variables locales) del código donde se crea. Task.detached no hereda ningún contexto, operando de manera independiente.
60. ¿Cómo cancelas una tarea asíncrona en SwiftUI? Guardando la referencia al objeto Task y llamando a .cancel(), o automáticamente cuando la vista desaparece si la tarea se creó usando el modificador .task.
61. ¿Qué es el protocolo Sendable? Define tipos seguros para pasar a través de límites concurrentes (entre Actores). Tipos por valor y Actores son implícitamente Sendable.
62. ¿Cómo integras APIs basadas en delegados con async/await? Utilizando withCheckedContinuation o withCheckedThrowingContinuation para pausar la función asíncrona y reanudarla cuando el delegado responda.
63. ¿Reemplazará Async/Await a Combine? No del todo. Async/Await es excelente para operaciones de un solo disparo (peticiones de red). Combine es superior para procesar flujos de eventos reactivos continuos en el tiempo (como la escritura de un usuario en un TextField).
64. ¿Qué es un AsyncStream? Es la forma nativa de la concurrencia de Swift de devolver múltiples valores en el tiempo (reemplazando parcialmente a los Publishers de Combine).
65. ¿Qué hace un TaskGroup? Permite ejecutar un número dinámico de tareas asíncronas concurrentes de forma estructurada, esperando a que todas terminen o agregando sus resultados.
66. Explica CurrentValueSubject frente a PassthroughSubject en Combine. CurrentValueSubject guarda un estado inicial y recuerda el último valor emitido. PassthroughSubject solo emite eventos sin almacenar estado.
67. ¿Cómo evitas pérdidas de memoria en Combine? Almacenando la suscripción (AnyCancellable) en un Set de cancelables. Si el objeto contenedor se deasigna, las suscripciones se cancelan automáticamente.
68. ¿Qué es el Data Race Safety en Swift 6? Es la validación estricta del compilador que garantiza matemáticamente en tiempo de compilación que tu código no tendrá condiciones de carrera en memoria.
69. ¿Cómo difieres una tarea en milisegundos usando concurrencia moderna? Usando try await Task.sleep(nanoseconds: 1_000_000) o en versiones nuevas Task.sleep(for: .milliseconds(1)).
70. ¿Qué es un Global Actor? Un actor que proporciona aislamiento a variables o funciones esparcidas por toda la aplicación, siendo @MainActor el ejemplo más famoso integrado en Xcode.
VI. Multiplataforma: iOS, macOS y watchOS
71. Como iOS Developer, ¿cómo gestionas código exclusivo para macOS en una app universal? Usando las directivas de compilación del procesador, como #if os(macOS), para compilar u omitir bloques de código específicos por plataforma.
72. ¿Qué es MenuBarExtra y dónde se usa? Es una estructura de SwiftUI que permite crear utilidades que viven en la barra de menú superior, exclusivamente para macOS.
73. Explica el uso de WindowGroup frente a DocumentGroup. WindowGroup crea una jerarquía de ventanas estándar para la app. DocumentGroup está diseñado para aplicaciones multiplataforma centradas en la creación y edición de archivos (como Pages).
74. ¿Cómo gestionas el control digital (Digital Crown) en watchOS? Usando el modificador .focusable() junto con .digitalCrownRotation() para leer los valores de entrada de la corona del reloj.
75. ¿Qué paradigma de navegación prefieres en iPadOS/macOS frente a iOS? En pantallas grandes, se debe favorecer la navegación de 2 o 3 columnas (NavigationSplitView), mientras que en iOS y watchOS el estándar es la pila de navegación (NavigationStack).
76. ¿Cómo optimizas el consumo de batería en una app para watchOS usando SwiftUI? Utilizando TimelineViewpara actualizaciones de pantalla programadas o integrando WidgetKit para mostrar complicaciones sin ejecutar la app principal.
77. ¿Qué es el Hover Effect y dónde es relevante? Es un modificador (.hoverEffect()) crítico para iPadOS (usando el Magic Keyboard) y VisionOS, que indica interactividad cuando el puntero pasa sobre una vista.
78. ¿Cómo manejas atajos de teclado multiplataforma? Agregando el modificador .keyboardShortcut() a los botones. Funcionan nativamente conectando teclados físicos a dispositivos iOS o directamente en el Mac.
79. Explica la importancia de ViewThatFits. Introducido en iOS 16, permite definir varias vistas; SwiftUI evaluará y renderizará la primera vista que quepa sin truncarse en la pantalla (muy útil de iPhone a watchOS).
80. ¿Cómo gestionas las notificaciones interactivas multiplataforma? Implementando un UNNotificationContentExtension donde la interfaz de usuario de la notificación se puede construir usando SwiftUI en todos los sistemas operativos de Apple.
81. ¿Cómo adaptas los comandos de menú (Menu Bar) en macOS y iPadOS? Modificando el contenido principal en App usando el método .commands { ... } para agregar acciones a la barra superior del sistema.
82. ¿Qué es Mac Catalyst frente a una app nativa en SwiftUI para macOS? Catalyst envuelve código UIKit para correr en Mac. SwiftUI moderno nativo compila utilizando AppKit por debajo, ofreciendo un mejor rendimiento y look-and-feel nativo en macOS.
83. ¿Qué desafíos presenta el teclado virtual en watchOS? No existe un teclado completo; se depende de respuestas rápidas, dictado de voz o Scribble. Las entradas de texto deben limitarse con .textContentType().
84. ¿Cómo se comparten recursos gráficos entre plataformas en Xcode? Utilizando el catálogo de Assets(.xcassets), marcando los recursos como universales o asignando versiones específicas por dispositivo o plataforma.
85. Explica el uso de Size Classes y TraitCollection en SwiftUI. Aunque abstraídos por @Environment(\.horizontalSizeClass), permiten detectar si la app está en un entorno compacto (iPhone vertical) o regular (iPad, macOS) para alterar el layout.
VII. Xcode, Herramientas, Testing y CI/CD
86. ¿Por qué las SwiftUI Previews a veces fallan y cómo lo solucionas? A menudo fallan por inyección de dependencias faltante, como no proporcionar un .environmentObject() en la vista previa, o por errores en el tiempo de compilación. Usar datos Mock estáticos es vital.
87. ¿Qué herramienta en Instruments usarías para detectar redibujados innecesarios? La plantilla “SwiftUI” en Instruments. Te permite inspeccionar el conteo de View Body Executions para identificar cuellos de botella de rendimiento.
88. ¿Cómo implementas pruebas unitarias (Unit Tests) en vistas de SwiftUI? No se deben testear las vistas directamente. La buena programación Swift dicta extraer la lógica de negocio a un ViewModel testeable o usar frameworks como ViewInspector.
89. ¿Para qué se utiliza accessibilityIdentifier en pruebas de interfaz de usuario (UI Tests)? Para asignar un identificador de cadena único a los elementos de SwiftUI, permitiendo a XCTest encontrar componentes independientemente del idioma o texto mostrado.
90. ¿Cómo gestionas dependencias en proyectos grandes? Utilizando SPM (Swift Package Manager). Es nativo en Xcode, rápido y permite modularizar el proyecto separando características en paquetes locales independientes.
91. Explica qué es Xcode Cloud. Es la solución de integración y entrega continua (CI/CD) de Apple, integrada directamente en Xcode, para compilar, probar y distribuir apps en TestFlight automáticamente.
92. ¿Qué es SwiftLint y por qué usarlo? Una herramienta de terceros que aplica guías de estilo y convenciones en el código Swift, manteniendo la base de código consistente en equipos grandes.
93. ¿Cómo perfilas fugas de memoria (Memory Leaks) en Xcode? Usando el Memory Graph Debugger integrado en Xcode o la herramienta “Leaks” en Instruments para localizar referencias fuertes circulares.
94. ¿Para qué sirve #Preview frente al antiguo PreviewProvider? Introducido en Xcode 15, #Preview es una macro de Swift que reduce el código repetitivo necesario para generar vistas previas, haciéndolo mucho más conciso.
95. ¿Cómo mockeas solicitudes de red para Unit Testing? Usando URLProtocol o creando un protocolo para el cliente de red, inyectando un MockClient en las pruebas que devuelva datos locales en lugar de realizar llamadas a internet.
96. ¿Qué es Code Coverage y cómo lo habilitas? Mide el porcentaje de líneas de código que se ejecutan durante tus pruebas. Se habilita en la configuración del Scheme de Xcode, bajo la pestaña Test.
97. Explica cómo modularizas una app monolítica en Xcode. Creando múltiples Targets de frameworks o empaquetando módulos de características (ej. “Login”, “CoreNetwork”) a través de Local Swift Packages.
98. ¿Qué es el Sanitizer en Xcode y cuáles conoces? Son herramientas para atrapar errores en tiempo de ejecución. Destacan el Thread Sanitizer (detecta data races) y Address Sanitizer (detecta problemas de memoria).
99. ¿Cómo aseguras que el texto dinámico (Dynamic Type) funcione correctamente? Usando .font(.headline) en lugar de .font(.system(size: 16)), permitiendo que el sistema escale el texto automáticamente según las preferencias de accesibilidad del usuario.
100. Como Senior, ¿qué haces si Xcode se comporta de manera errática (ej. no compila sin errores lógicos)?Limpio el Build Folder (Cmd + Shift + K), borro la carpeta Derived Data, reinicio Xcode, o en última instancia, reinicio el Mac (la infalible triada del desarrollador Apple).
Conclusión
El rol del iOS Developer ha evolucionado de manera drástica. Superar una entrevista para iOS Senior Developer en SwiftUI requiere mucho más que memorizar conceptos; exige comprender el por qué de las decisiones de diseño del lenguaje y dominar las herramientas multiplataforma que ofrece Xcode. Ya sea gestionando concurrencia con async/await, arquitecturando código escalable con TCA, o adaptando vistas para iOS, macOS y watchOS, la programación Swift moderna es un ecosistema rico y desafiante.








