Core Data es un framework de gestión de datos de Apple que proporciona mapeo objeto-relacional para iOS, macOS, tvOS y watchOS. Automatiza el guardado, la recuperación y el filtrado de objetos en la aplicación, funcionando sobre SQLite, XML o almacenamiento binario. Según la Apple Core Data Documentation, el framework utiliza los conceptos de Managed Object Context y NSPersistentContainer para gestionar el stack de persistencia.
Puntos clave
Core Data es un framework de gestión de grafos de objetos y persistencia que forma parte de Cocoa Touch. Contrariamente a la creencia popular, Core Data no es una base de datos, sino una capa de gestión de objetos que puede usar SQLite como uno de sus almacenes. La tarea principal de Core Data es rastrear los cambios de objetos, gestionar su ciclo de vida y sincronizar el estado con el disco.
El framework proporciona un grafo de objetos donde cada Managed Object es supervisado por el contexto para detectar cambios. Al guardar, todos los objetos modificados, añadidos y eliminados se confirman en el almacén persistente en una sola transacción. Esto elimina la necesidad de que el desarrollador escriba consultas SQL y gestione transacciones manualmente.
Según las estadísticas de la Swift Developer Survey (2025), Core Data se utiliza en el 52% de las aplicaciones iOS que trabajan con datos locales. A pesar de la aparición de alternativas modernas (SwiftData, Realm), Core Data sigue siendo el framework principal en los proyectos existentes de Apple debido a su madurez y profunda integración con el sistema.
Utilice Core Data para proyectos con un modelo de datos de complejidad media, donde se necesiten relaciones entre objetos, deshacer cambios y caché automática mediante el mecanismo de faulting.
La arquitectura de Core Data se basa en el concepto de Managed Object Context — un área de trabajo que rastrea todos los cambios de objetos. El contexto admite deshacer/rehacer a través de NSUndoManager integrado, lo que permite implementar borradores y cancelación de acciones sin guardar manualmente instantáneas de estado. Al llamar a save(), el contexto confirma todos los cambios en una sola transacción en el almacén persistente, garantizando atomicidad y consistencia de datos.
El modelo de datos de Core Data se define en el archivo .xcdatamodeld — el editor visual de Xcode donde se describen todas las Entity, sus atributos y relaciones. En tiempo de compilación, el modelo se serializa en .momd y se carga a través de NSManagedObjectModel.
Entity es una descripción de tipo de datos, similar a una tabla en SQL. Cada Entity contiene un conjunto de Attributes — campos con nombre y tipo de dato (String, Integer, Date, Boolean, Data). A diferencia de Room, Core Data requiere la selección explícita del tipo para cada atributo a través del editor de modelos.
Relationship es una conexión entre Entity, similar a una clave foránea en SQL. Core Data admite todos los tipos de relaciones: uno-a-uno, uno-a-muchos y muchos-a-muchos. Para cada relación se configura una Delete Rule (Cascade, Nullify, Deny) — el comportamiento al eliminar el objeto relacionado.
| Delete Rule | Comportamiento al eliminar | Ejemplo de uso |
|---|---|---|
| Cascade | Elimina todos los objetos relacionados | Eliminar un pedido junto con sus líneas |
| Nullify | Anula la relación inversa | Eliminar un autor sin eliminar libros |
| Deny | Bloquea la eliminación si hay objetos relacionados | Proteger contra la eliminación de una categoría con productos |
Elegir una Delete Rule es crítico para la integridad de los datos: Cascade sin verificación puede eliminar un tercio de la base de datos, mientras que Deny puede bloquear la operación con un error poco claro. En código de producción, se recomienda Nullify con manejo manual de registros huérfanos.
En el editor de modelos de Xcode, el desarrollador puede definir no solo Entity y atributos, sino también constraints (restricciones de unicidad), índices para acelerar consultas y valores predeterminados para atributos. Todos los cambios del modelo se compilan en un archivo .momd, que se carga durante la inicialización de NSPersistentContainer. El versionado del modelo (Model Versioning) permite mantener múltiples versiones del esquema y realizar migraciones entre ellas.
NSPersistentContainer es un objeto único que gestiona el stack de Core Data desde iOS 10 y macOS 10.12. Encapsula NSManagedObjectModel, NSPersistentStoreCoordinator y NSManagedObjectContext, automatizando la carga del modelo y la configuración del almacén. Para versiones anteriores, el stack se construía manualmente, pero esto ya no se recomienda.
let container = NSPersistentContainer(name: "DataModel")
container.loadPersistentStores { _, error in
if let error { fatalError("Core Data load failed: \(error)") }
}
let context = container.viewContext
viewContext es el contexto principal vinculado al hilo principal. Todas las lecturas y actualizaciones de la interfaz se realizan a través de él. Para el rendimiento, se recomienda realizar la escritura de datos en un contexto hijo en segundo plano con sincronización posterior.
El coordinador NSPersistentStoreCoordinator conecta el modelo con el almacenamiento físico en disco. Core Data admite varios tipos de almacén: SQLite (recomendado), Binary e In-Memory. El almacén SQLite admite migraciones, copia de seguridad incremental y resistencia a fallos durante las operaciones de escritura.
NSFetchRequest es un objeto que describe una consulta al almacén de Core Data. Contiene el nombre de la Entity, el predicado de filtro, los descriptores de ordenación y la configuración de recuperación. La consulta se ejecuta mediante context.fetch(), que devuelve un array de NSManagedObject.
let request = NSFetchRequest<User>(entityName: "User")
request.predicate = NSPredicate(format: "age >= %d", 18)
request.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
request.fetchLimit = 50
let results = try context.fetch(request)
NSPredicate admite condiciones complejas: LIKE, IN, BETWEEN, CONTAINS[c] (insensible a mayúsculas/minúsculas), SUBQUERY para consultas anidadas en Entity relacionadas. Core Data también es compatible con NSFetchedResultsController — una clase para la carga reactiva de datos en UITableView, que rastrea automáticamente los cambios y actualiza la tabla con secciones animadas.
Trabajar con Core Data en una aplicación multihilo requiere el cumplimiento estricto de reglas: NSManagedObject no se puede pasar directamente entre hilos. Cada hilo (o cola) debe usar su propio contexto. El enfoque principal es crear un NSManagedObjectContext hijo con una cola privada (NSPrivateQueueConcurrencyType) para escritura y viewContext para lectura.
El contexto hijo guarda en el padre, y luego el padre guarda en el almacén de disco. Esto garantiza que los cambios no bloqueen el hilo principal y que la interfaz de usuario siempre vea un estado coherente a través de mergeChanges o la actualización automática de viewContext al guardar.
Core Data utiliza faulting — un mecanismo de carga diferida para objetos relacionados. Al recuperar un User sin solicitar sus direcciones, los objetos Address relacionados no se cargan hasta que se accede a ellos mediante notación de punto. Faulting ahorra memoria y acelera la carga, pero puede causar accesos inesperados al disco en el hilo principal si no se controla el acceso en contextos en segundo plano.
Para un multihilo eficiente, use NSBatchInsertRequest y NSBatchDeleteRequest para inserciones y eliminaciones masivas sin cargar objetos en memoria — esto es crítico para la sincronización de datos con el servidor.
Las operaciones por lotes se ejecutan directamente a nivel de NSPersistentStoreCoordinator, sin pasar por el contexto y el grafo de objetos. Esto permite insertar 10.000 registros en milisegundos sin crear 10.000 instancias de NSManagedObject en memoria. Después de ejecutar una solicitud por lotes, el contexto debe actualizarse mediante mergeChangesFromContextDidSaveNotification para que la interfaz refleje los nuevos datos. Apple recomienda operaciones por lotes para la carga inicial de datos y la sincronización nocturna con el servidor.
Para el seguimiento de cambios en Core Data se utiliza NSPersistentHistoryTracking — un mecanismo que registra cada transacción (inserción, actualización, eliminación) en un historial separado. Activar el historial permite sincronizar datos entre diferentes procesos y aplicaciones que trabajan con el mismo archivo SQLite, por ejemplo entre la aplicación principal y una Notification Service Extension. La activación se realiza mediante NSPersistentStoreDescription con el indicador persistentHistoryTrackingKey, y la lectura mediante NSPersistentHistoryChangeRequest con filtrado por fecha y tipo de transacción.
Para la depuración y el análisis de rendimiento de Core Data se utiliza la herramienta Core Data Profiler del conjunto Instruments en Xcode en macOS. Muestra todas las operaciones de recuperación, inserción, eliminación y guardado con la duración de cada operación y el número de objetos cargados en tablas y gráficos de línea de tiempo. El desarrollador puede identificar áreas problemáticas: múltiples recuperaciones de la misma consulta (falta de caché), fugas de objetos fault durante el desplazamiento de la tabla o bloqueo del hilo principal debido a la carga síncrona de entidades relacionadas. Se recomienda ejecutar la creación de perfiles en un dispositivo real y no en un simulador, ya que el rendimiento del simulador no refleja el comportamiento real de la aplicación en un iPhone o iPad.
Preguntas frecuentes
Core Data no es una base de datos, sino una capa de gestión de objetos que puede usar SQLite como almacén. A diferencia de SQLite puro, Core Data rastrea los cambios de objetos, gestiona deshacer y proporciona un grafo de objetos con faulting y caché. SQLite da más control sobre las consultas, pero requiere escribir SQL y gestionar transacciones manualmente.
Core Data admite la migración ligera (Lightweight Migration) para cambios no destructivos: añadir un atributo, renombrar, establecer un valor predeterminado. Para cambios complejos, se crea un Mapping Model. La migración ligera se activa mediante el indicador shouldMigrateAutomatically en NSPersistentStoreDescription.
Sí, Core Data se integra con SwiftUI a través del envoltorio @FetchRequest para consultas y @ObservedObject para suscripción a cambios. SwiftUI actualiza automáticamente la View cuando cambia un ManagedObject, lo que hace que Core Data y SwiftUI sean un stack compatible para la gestión de estado.
Un fault es un marcador de posición ligero en el grafo de Core Data que no contiene los datos del objeto relacionado. Cuando se establece un fault (mediante refreshObject:), los datos se descargan de la memoria. Cuando se accede a una propiedad, el fault se llena automáticamente con datos del almacén — este es un mecanismo de carga diferida que optimiza el uso de memoria.
Para las pruebas, use el tipo de almacén In-Memory: NSPersistentStoreDescription con NSInMemoryStoreType. El contenedor se crea con el modelo del bundle de pruebas. Después de cada prueba, elimine todos los objetos o vuelva a crear el contenedor — esto garantiza el aislamiento de los casos de prueba entre sí.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también