Contenido del curso
Arquitectura
Gestión de Datos en SwiftData
- 8

Uso de SWIFTDA para Persistencia de Datos en iOS 17
04:31 min - 9

Cómo grabar datos con SwiftData
Viendo ahora - 10

Implementación de Queries con Predicados en Swift Data
11:08 min - 11

Corrección automática y actualización de registros en SWIFTDA
06:59 min - 12

Eliminar registros y calcular totales en SwiftData
04:20 min
Gestión de Datos en Realm
¿Swift Data o Realm?
Cómo grabar datos con SwiftData
Resumen
Integrar SwiftData en un proyecto iOS implica crear una capa de servicio dedicada, definir entidades con el macro @model y conectar todo con un protocolo de base de datos. Si vienes trabajando con un mock service, este es el momento de reemplazarlo por persistencia real usando el framework nativo de Apple.
La idea es mantener el código organizado, separar responsabilidades y dejar lista la primera función para grabar registros en la base de datos.
¿Cómo organizar la carpeta de servicios para SwiftData?
La estructura del proyecto importa tanto como el código. SwiftData se trata como un proveedor más de servicios de base de datos, así que vive en su propia carpeta dentro del folder de servicios.
Dentro de SwiftData Database Service se crean dos subcarpetas clave:
Entities, donde vive el modelo que representa los datos en la base.- El archivo de implementación del servicio, que adopta el protocolo de base de datos.
Esta separación replica la lógica que ya existía con el Mock Database Service, pero apuntando a persistencia real [02:00].
¿Qué es una entidad en SwiftData? Es la clase marcada con
@modelque representa un registro en la base de datos. SwiftData la usa como plantilla para crear, leer y actualizar filas.
¿Cómo se define la entidad SDRecord con el macro @model?
La entidad se llama SDRecord: SD por SwiftData y Record porque representa un registro. El primer paso es importar SwiftData y declarar la clase con el macro @model, que le indica al framework que esta clase será persistida [02:30].
Las propiedades replican el modelo que ya conocen las vistas y los view models:
id: identificador propio dentro de la base de datos.recordID: referencia al ID del registro en el modelo de la aplicación.title: título del registro.date: fecha de tipoDate.type: cadena que representa el tipo.amount: valor numérico de tipoDouble.
El macro @model exige un inicializador, así que se crea un init que recibe estos parámetros. El id cumple doble función: es la llave principal y también el valor que se usará en queries y consultas posteriores [03:30].
¿Por qué se guarda type como String si en la app es RecordType?
La base de datos almacena tipos primitivos para mantener compatibilidad y simplicidad. Por eso type se guarda como String y se convierte a RecordType solo cuando la entidad se transforma en un record de la aplicación.
¿Cómo conectar SDRecord con ToRecordProtocol?
El protocolo ToRecordProtocol permite que cualquier entidad de base de datos exponga su versión como record de la aplicación. En lugar de mezclar lógica dentro de la clase, se usa una extension de SDRecord que adopta el protocolo [04:30].
Dentro de la función exigida por el protocolo, el mapeo queda así:
- El
idse mantiene tal cual. title,dateyamountpasan directo.typese convierte desdeStringaRecordTypeusando el inicializador conrawValue, con un valor por defecto como red de seguridad.
Este patrón mantiene a la vista y al view model aislados de los detalles de SwiftData. Solo conocen el record de la aplicación, nunca la entidad cruda.
¿Cómo implementar SDDatabaseService con ModelContainer y ModelContext?
El archivo SDDatabaseService adopta el DatabaseServiceProtocol y usa SwiftData como motor real de persistencia. Aquí aparece un detalle crítico: la clase se marca con @MainActor porque SwiftData requiere que sus operaciones corran en el hilo principal [06:00].
Para que la base funcione, se necesitan dos piezas que SwiftData expone:
- Un
ModelContainer, que conoce las entidades que va a manejar. - Un
ModelContext, que es el espacio donde ocurren las inserciones, lecturas y guardados.
Ambos se inicializan dentro del init de la clase. El container se crea con try ModelContainer(for: SDRecord.self, configurations: ModelConfiguration(isStoredInMemoryOnly: false)). Con ese contenedor listo, el context se inicializa como un nuevo ModelContext que recibe el container recién creado.
¿Para qué sirve isStoredInMemoryOnly en false? Le indica a SwiftData que persista los datos en disco en lugar de mantenerlos solo en memoria. Así la información sobrevive entre sesiones de la app.
¿Qué retornar mientras las funciones del protocolo no están implementadas?
Para que la app compile y no rompa en ejecución, las funciones del protocolo devuelven valores por defecto: una lista vacía, false donde se espera un booleano y una tupla (0.0, 0.0) donde se esperan totales. Son placeholders hasta que cada función reciba su lógica real.
¿Cómo grabar un nuevo registro con context.insert y context.save?
La primera función completa es la que graba un record. El flujo tiene tres pasos claros [08:30]:
- Crear un
SDRecorda partir del record recibido como parámetro, mapeando cada propiedad. Eltypese transforma conrecord.type.rawValuepara guardarse comoString. - Insertar la entidad en el contexto con
context.insert(sdRecord). - Persistir los cambios con
try context.save().
Todo el bloque vive dentro de un do-catch. Si la inserción y el guardado funcionan, la función retorna true. Si SwiftData lanza una excepción, el catch retorna false y la app sabe que la operación falló sin caerse.
Este patrón se va a repetir en las próximas funciones del servicio: leer registros, filtrar por tipo y calcular totales. La base ya quedó montada y lista para crecer.
¿Cómo organizas tú la capa de persistencia en tus proyectos iOS? Cuéntame en los comentarios qué patrón usas antes de migrar a SwiftData.