Francisco José García Navarro
June 6, 2023WWDC 2023: todo lo que un desarrollador iOS necesita saber
" El resumen técnico del día después — macros, SwiftData, @Observable, Vision Pro y el mayor salto de SwiftUI hasta la fecha "
Acabo de terminar de digerir el keynote y el State of the Union de la WWDC 2023, y necesito procesar lo que acaba de pasar. Apple ha presentado un dispositivo nuevo (Vision Pro), ha reescrito los cimientos de cómo gestionamos datos en SwiftUI, ha introducido macros en Swift, y ha lanzado un reemplazo para Core Data. Todo en una sola tarde.
Si la WWDC 2022 fue el año de la navegación y la concurrencia, la WWDC 2023 es el año de la observación, la persistencia y las macros. Son cambios que van a redefinir cómo escribimos código Swift durante los próximos cinco años.
Voy a desglosar todo lo relevante para quienes trabajamos en apps iOS en producción. Vision Pro acapara los titulares, pero las novedades en Swift 5.9, SwiftUI y SwiftData son lo que realmente va a impactar tu día a día como developer.
Swift 5.9: las macros lo cambian todo
La novedad estrella de Swift 5.9 son las macros. Y no exagero al decir que cambian fundamentalmente lo que es posible hacer con el lenguaje.
Las macros transforman tu código fuente añadiendo código adicional en tiempo de compilación. Nunca eliminan ni modifican código existente — solo añaden. Hay dos categorías principales:
Macros freestanding (precedidos por #): se usan en cualquier parte del código. El ejemplo canónico es #Predicate, que permite escribir predicados type-safe con closures para usar con SwiftData y las operaciones de colecciones.
let predicate = #Predicate<User> { user in
user.age > 18 && user.name.contains("García")
}
Macros attached (precedidos por @): se adjuntan a declaraciones. Los más importantes que veremos hoy son @Observable y @Model, que componen múltiples roles de macro para transformar clases enteras.
Pero lo más potente es que puedes crear tus propias macros. Un ejemplo sencillo: una macro #URL que valida URLs hard-coded en tiempo de compilación, convirtiendo un URL? en un URL no-optional porque el compilador ya ha verificado que la URL es válida.
// Antes: URL opcional, puede fallar en runtime
let url = URL(string: "https://api.example.com/users")!
// Con macro: validado en compilación, nunca falla
let url = #URL("https://api.example.com/users")
Las macros se implementan como paquetes Swift separados usando SwiftSyntax. Se ejecutan en un sandbox y solo pueden inspeccionar y generar código — no pueden acceder al filesystem ni a la red. En Xcode 15, puedes hacer "Expand Macro" para ver exactamente qué código genera cada macro. Transparencia total.
Para equipos enterprise, esto abre la puerta a reducir boilerplate masivamente: generación de mocks, conformancias automáticas, validaciones en compilación. El potencial es enorme.
Parameter packs (variadic generics)
Swift 5.9 también introduce parameter packs (SE-0393, SE-0398, SE-0399), la característica más solicitada del lenguaje desde hace años. Permiten escribir funciones genéricas que aceptan un número arbitrario de parámetros de tipo, cada uno con su propio tipo.
func all<each T: Equatable>(
_ original: repeat each T,
equal copy: repeat each T
) -> Bool {
(repeat (each original) == (each copy))
}
Esto parece abstracto, pero es lo que permite a Apple construir APIs como las nuevas vistas de SwiftUI que aceptan contenido variable sin necesidad de sobrecargas para 2, 3, 4... 10 parámetros. Es infraestructura de lenguaje que habilita mejores frameworks.
Más novedades del lenguaje
- if/switch como expresiones (SE-0380): puedes usar
ifyswitchdirectamente como valores de retorno o asignaciones.let value = if condition { "a" } else { "b" }. - Interoperabilidad Swift/C++: Xcode 15 soporta interop bidireccional entre Swift y C++. Para proyectos legacy con código C++, esto es un game changer.
- Noncopyable types (
~Copyable): permiten expresar ownership exclusivo, útil para wrappers de recursos del sistema.
@Observable: SwiftUI se libera de Combine
Este es, para mí, el cambio más importante de la WWDC 2023. El macro @Observable y el nuevo framework Observation simplifican radicalmente el flujo de datos en SwiftUI.
Hasta ahora, para que una vista respondiera a cambios en un modelo, necesitabas: conformar a ObservableObject, marcar cada propiedad con @Published, y usar @ObservedObject o @StateObject en la vista. Si te olvidabas un @Published, la UI no se actualizaba. Si usabas @ObservedObject cuando necesitabas @StateObject, tenías bugs de ciclo de vida. Era una fuente constante de errores.
Con @Observable, todo eso desaparece:
import Observation
@Observable
final class UserStore {
var users: [User] = []
var isLoading = false
func fetch() async {
isLoading = true
users = await api.fetchUsers()
isLoading = false
}
}
La vista simplemente usa el modelo, sin property wrappers especiales:
struct UserListView: View {
var store: UserStore
var body: some View {
List(store.users) { user in
Text(user.name)
}
}
}
SwiftUI detecta automáticamente qué propiedades accede cada vista durante la ejecución de body, y solo invalida la vista cuando esas propiedades específicas cambian. Si isLoading cambia pero la vista solo lee users, no se redibuja. Esto resuelve de raíz el problema de rendimiento que arrastraba ObservableObject.
El nuevo modelo de property wrappers queda simplificado:
@State: para value types y reference types@Observableque la vista posee.@Environment: para inyectar@Observableen el entorno (reemplaza@EnvironmentObject).@Bindable: para crear bindings bidireccionales desde un tipo@Observable.
Se acabó la confusión entre @StateObject, @ObservedObject y @EnvironmentObject. La limitación: @Observable requiere iOS 17. Para apps que soporten iOS 16 o anterior, seguirás con ObservableObject. Pero para nuevos proyectos, esto simplifica enormemente la arquitectura.
SwiftData: Core Data para el siglo XXI
Apple lanza SwiftData, un framework de persistencia nativo en Swift construido sobre los cimientos de Core Data. Si has sufrido Core Data (y quién no), esto es lo que llevábamos esperando años.
El modelo se define con el macro @Model:
import SwiftData
@Model
class Project {
var name: String
var deadline: Date
var isCompleted: Bool
@Relationship(deleteRule: .cascade)
var tasks: [Task] = []
init(name: String, deadline: Date) {
self.name = name
self.deadline = deadline
self.isCompleted = false
}
}
@Model genera automáticamente conformancia a PersistentModel y Observable. SwiftData infiere el schema desde las propiedades, soporta tipos primitivos, Codable, enums y relaciones. Los atributos se personalizan con @Attribute(.unique), @Relationship y @Transient.
La integración con SwiftUI es directa:
struct ProjectListView: View {
@Query(sort: \.deadline)
var projects: [Project]
@Environment(\.modelContext)
var context
var body: some View {
List(projects) { project in
ProjectRow(project: project)
}
}
}
@Query reemplaza @FetchRequest con soporte para los nuevos predicados type-safe via #Predicate (adiós NSPredicate con strings). SwiftData soporta versionado de schemas con migraciones ligeras automáticas, persistencia en iCloud (CloudKit), y generación de clases SwiftData desde modelos Core Data existentes para migración gradual.
Mi valoración: la API es elegante y moderna. Sin embargo, es una versión 1.0, y eso siempre exige cautela en producción. Para apps nuevas targeting iOS 17+, es una opción muy atractiva. Para apps enterprise en producción con Core Data, yo esperaría a que madure. Core Data sigue ahí y no va a ningún sitio.
SwiftUI 5: widgets interactivos, animaciones keyframe y MapKit nativo
Widgets interactivos
La feature más pedida de WidgetKit llega por fin: los widgets ahora pueden contener Button y Toggle que ejecutan código de tu app mediante App Intents, sin lanzar la app en primer plano. Las transiciones y animaciones SwiftUI también funcionan en widgets.
Además, los widgets llegan a nuevos lugares: pantalla de bloqueo en iPadOS, StandBy en iPhone, y escritorio de macOS Sonoma. El mismo código WidgetKit funciona en todas estas superficies.
Para apps enterprise que ya tienen widgets, añadir interactividad es relativamente sencillo y tiene un impacto directo en engagement. Un botón de "marcar como completado" en un widget de tareas, o un toggle de "iniciar tracking" en una app de logística, son features con ROI inmediato.
Animaciones: keyframes y fases
SwiftUI 5 introduce dos APIs de animación potentes:
KeyframeAnimator permite animaciones multi-propiedad con control preciso de timing. Defines tracks independientes para cada propiedad con diferentes curvas de interpolación:
KeyframeAnimator(initialValue: AnimationValues(), trigger: trigger) { values in
MyView()
.scaleEffect(values.scale)
.rotationEffect(values.rotation)
} keyframes: { _ in
KeyframeTrack(\.scale) {
SpringKeyframe(1.2, duration: 0.3)
SpringKeyframe(1.0, spring: .bouncy)
}
KeyframeTrack(\.rotation) {
LinearKeyframe(.degrees(0), duration: 0.2)
CubicKeyframe(.degrees(360), duration: 0.5)
}
}
PhaseAnimator define secuencias de estados de animación que se ejecutan cíclicamente o por trigger. Las animaciones spring son ahora el default en iOS 17, lo cual mejora la sensación de fluidez sin esfuerzo adicional.
MapKit para SwiftUI
MapKit recibe una API nativa de SwiftUI completamente nueva: Map con Marker, Annotation, MapPolyline, MapPolygon, y MapCircle. Soporte para Look Around inline, selección de features del mapa, y estilos (standard, imagery, hybrid). Si hasta ahora usabas UIViewRepresentable para embeber MKMapView, ya no lo necesitas.
ScrollView mejorado
ScrollView gana .scrollPosition(id:) para scroll programático, .scrollTargetBehavior(.paging) para paginación nativa, y .containerRelativeFrame() para sizing relativo al contenedor. Efectos visuales con .scrollTransition() permiten transformaciones basadas en la posición del scroll. Son mejoras que resuelven problemas reales que antes requerían UIScrollView con UIViewRepresentable.
Xcode 15: #Preview, String Catalogs y firma de dependencias
Xcode 15 trae mejoras que impactan directamente en la productividad diaria:
Macro #Preview: la nueva sintaxis de previews es más limpia y funciona con SwiftUI, UIKit y AppKit:
#Preview("User Profile") {
UserProfileView(user: .mock)
}
// UIKit también:
#Preview("Settings") {
let vc = SettingsViewController()
vc.user = .mock
return vc
}
String Catalogs (.xcstrings): reemplazan los archivos .strings y .stringsdict con un formato unificado que muestra el estado de traducción por idioma. Migración con click derecho desde archivos existentes. Back-deployable a cualquier OS. Soporte mejorado de concordancia gramatical para español, portugués y alemán.
UIKit: viewIsAppearing: un nuevo callback de ciclo de vida que se llama entre viewWillAppear y viewDidAppear, cuando la vista ya está en la jerarquía con traits y geometría correctos. Se back-deploya a iOS 13. Para quienes mantenemos apps UIKit, esto es oro. Resuelve el eterno problema de necesitar geometría real antes de que termine la animación de transición.
Verificación de firmas de dependencias: Xcode 15 verifica las firmas digitales de paquetes SPM, alertando si una dependencia ha sido modificada. Seguridad supply-chain que llega tarde pero bienvenida para proyectos enterprise.
Otras mejoras: code completion mejorado con modelos de ML, navigator de bookmarks, informes de tests rediseñados con insights de patrones, integración de OSLog en la consola, y simuladores opcionales para reducir el tamaño de descarga.
TipKit: tooltips nativos para onboarding
Nuevo framework para mostrar tooltips contextuales que ayudan a los usuarios a descubrir features de la app. Disponible en iOS 17, macOS Sonoma, watchOS 10 y tvOS 17.
struct FavoritesTip: Tip {
var title: Text { Text("Añadir a favoritos") }
var message: Text? { Text("Pulsa el corazón para guardar este elemento.") }
var image: Image? { Image(systemName: "heart") }
}
// En la vista
TipView(FavoritesTip())
TipKit incluye un sistema de reglas para mostrar tips en el momento adecuado (basadas en eventos del usuario o parámetros), control de frecuencia (máximo un tip al día), sincronización entre dispositivos vía iCloud, e invalidación automática cuando el usuario ya ha usado la feature.
Para apps enterprise complejas con flujos que los usuarios no descubren solos, esto es infinitamente mejor que construir tu propio sistema de onboarding. Y la UI es consistente con los tips nativos de Apple.
UIKit sigue vivo y coleando
Apple no ha abandonado UIKit. En iOS 17:
- Sistema de traits rediseñado: API basada en closures para trabajar con
UITraitCollection. Puedes definir custom traits y registrar callbacks cuando cambian. Mucho más limpio que overridetraitCollectionDidChange. - SF Symbols animados: las animaciones de símbolos ahora son configurables con efectos como
.bounce,.pulse,.variableColor,.replace. Funciona en UIKit y SwiftUI. - Empty state views: configuración nativa para estados vacíos en collection views.
- UIPageControl con progreso: indicador de progreso fraccionario entre páginas.
- Palette menus:
UIMenucon opción.displayAsPalettepara mostrar items en fila. - Status bar adaptativo: en iOS 17, la barra de estado adapta automáticamente entre claro y oscuro según el contenido de debajo.
Y no lo olvides: viewIsAppearing se back-deploya a iOS 13. Es la mejora de UIKit más práctica de esta WWDC.
performAccessibilityAudit(): tests de accesibilidad automatizados
Esta es una novedad que me emociona especialmente. Ahora puedes ejecutar auditorías de accesibilidad automatizadas desde UI tests:
func testAccessibility() throws {
let app = XCUIApplication()
app.launch()
try app.performAccessibilityAudit()
}
Con una sola línea, Xcode verifica labels, traits, contraste, tamaños táctiles y más. Puedes filtrar por categorías y excluir issues conocidos. Esto permite integrar verificación de accesibilidad en tu pipeline CI/CD de forma trivial.
Para equipos que necesitan cumplir normativas de accesibilidad (WCAG, Section 508, o los estándares europeos EN 301 549), poder automatizar estas auditorías es un cambio fundamental. Ya no hay excusa para no testear accesibilidad.
Vision Pro y visionOS: la nueva plataforma
Apple presenta Vision Pro, su "computadora espacial" con chips M2 + R1 y visionOS, el primer sistema operativo espacial. Es el primer hardware completamente nuevo de Apple desde el Apple Watch en 2015.
Para developers iOS, lo relevante es:
- Las apps SwiftUI existentes funcionan en visionOS como ventanas 2D sin modificación. Esto valida la inversión en SwiftUI.
- RealityKit se convierte en el framework principal para contenido 3D, con una nueva API declarativa estilo SwiftUI.
- UIKit y SwiftUI proporcionan comportamientos específicos de visionOS (hover effects, materiales, profundidad) automáticamente al compilar para la plataforma.
- El simulador de Xcode 15 permite probar experiencias visionOS sin tener el hardware.
Mi opinión: Vision Pro es fascinante como plataforma, pero a $3.499 y con disponibilidad limitada, su impacto inmediato en apps enterprise es mínimo. Sin embargo, si ya estás en SwiftUI, gran parte del trabajo de adaptación está hecho. Vigila esta plataforma, pero no dejes de lado lo que importa hoy: iOS 17, Swift 5.9 y SwiftData.
Hardware y más novedades
- MacBook Air de 15": pantalla Liquid Retina de 15.3", chip M2, 18 horas de batería, $1.299. La mejor máquina de desarrollo portátil relación calidad-precio.
- Mac Studio y Mac Pro: actualizados con M2 Max y M2 Ultra. El Mac Pro con M2 Ultra cierra la transición a Apple Silicon — ya no hay Macs con Intel.
- watchOS 10: rediseño visual significativo, widgets apilados accesibles con Digital Crown, y navegación vertical por defecto. WidgetKit unificado entre watchOS, iOS y macOS.
- macOS Sonoma: widgets en el escritorio, Game Porting Toolkit para traer juegos de Windows, screensavers de vídeo, y Stage Manager mejorado.
- StoreKit para SwiftUI: nuevas vistas declarativas para compras in-app (
ProductView,StoreView,SubscriptionStoreView). Construir una pantalla de suscripción profesional pasa de semanas a horas.
Conclusión: qué hacer ahora
La WWDC 2023 es, posiblemente, el mayor salto de SwiftUI desde su lanzamiento en 2019. El macro @Observable resuelve problemas fundamentales de arquitectura y rendimiento. SwiftData promete modernizar la persistencia. Las macros de Swift 5.9 abren posibilidades que antes requerían generación de código externa.
Si tuviera que elegir tres acciones concretas para un equipo iOS enterprise:
- Adopta
@Observableen tu próximo feature targeting iOS 17. La simplificación del flujo de datos es inmediata y el rendimiento mejora significativamente. Si tu arquitectura es MVVM, los ViewModels se vuelven más simples sinObservableObjectni@Published. - Añade
performAccessibilityAudit()a tus UI tests hoy. No requiere iOS 17 en producción — lo ejecutas en el simulador en tu CI. Una línea de código que detecta problemas de accesibilidad automáticamente. - Haz interactivos tus widgets existentes. Un
ButtonoToggleen un widget con App Intents tiene un impacto desproporcionado en engagement, y el esfuerzo de implementación es bajo.
Sobre SwiftData: evalúalo seriamente para proyectos nuevos, pero no migres tu Core Data stack en producción todavía. Dale tiempo a la 1.0 para madurar.
Y sobre Vision Pro: es el futuro, pero tu app iOS es el presente. Si ya inviertes en SwiftUI, estarás preparado cuando llegue el momento.
Ha sido una WWDC memorable. Las macros y @Observable van a definir cómo escribimos Swift durante los próximos años. Toca ponerse a estudiar.
¿Necesitas ayuda con la adopción?
💡 ¿Tienes un proyecto que necesita migración? Podemos ayudarte a hacer la transición de forma eficiente y sin interrupciones en tu flujo de desarrollo.
📩 Contáctanos aquí para más información.
Sobre el autor
Francisco José García Navarro
Francisco José García Navarro es el cofundador y CEO de AtalayaSoft e ingeniero de software iOS experimentado con más de 25 años en desarrollo de software. Especializado en aplicaciones iOS nativas, Francisco tiene una amplia trayectoria trabajando con clientes de alto perfil como Banco Santander, Fox International Channel, Repsol y National Geographic.