Core Data es un framework de Apple para gestionar un grafo de objetos en aplicaciones iOS y macOS. Proporciona persistencia de datos, seguimiento de cambios, operaciones de deshacer e integración con la UI a través de NSFetchedResultsController. Según la documentación de Apple Developer (2025), Core Data no es una base de datos — es una capa de modelado de objetos que por defecto usa SQLite como almacenamiento persistente para cargar y guardar objetos.
Puntos clave
Core Data es un framework de gestión de grafos de objetos y persistencia que forma parte del SDK Cocoa Touch de Apple. Proporciona una interfaz orientada a objetos para trabajar con datos: el desarrollador opera con entidades, atributos y relaciones, mientras que Core Data transforma estos objetos en registros de base de datos relacional bajo el capó.
Core Data se presentó en Mac OS X 10.4 Tiger (2005) para macOS y se portó a iOS 3.0 (2009). En más de 20 años, el framework ha evolucionado de una simple capa de abstracción sobre SQLite a un stack completo con soporte de sincronización en la nube a través de NSPersistentCloudKitContainer, múltiples hilos mediante gestión automática de contextos y carga asíncrona con Swift Concurrency.
Según una encuesta de desarrolladores iOS de Slack Community (2025), Core Data se usa en el 68% de las aplicaciones iOS comerciales para almacenamiento local de datos. A pesar de las críticas por su complejidad y arquitectura en capas, el framework sigue siendo el estándar para aplicaciones Apple gracias a su estrecha integración con el sistema, coste cero (incluido en el SDK) y soporte de sincronización con iCloud.
Un error común es considerar Core Data como una base de datos. El framework no ejecuta consultas SQL directamente y no es un SGBD. Core Data es una capa de gestión de grafos de objetos que puede usar almacenamiento SQLite, Binary o In-Memory para la persistencia. Analogía: Core Data es como Hibernate o Entity Framework pero para el ecosistema Apple, y SQLite debajo es como MySQL bajo Hibernate.
El stack de Core Data consta de cuatro componentes interconectados: NSManagedObjectModel (esquema de datos), NSPersistentStoreCoordinator (coordinador de almacenamiento), NSManagedObjectContext (contexto de trabajo) y NSPersistentContainer (un contenedor unificado que combina los tres desde iOS 10). NSPersistentContainer automatiza la creación y configuración del stack.
Cada componente realiza una función estrictamente definida. NSManagedObjectModel carga el archivo .xcdatamodeld con las descripciones de las entidades. NSPersistentStoreCoordinator conecta el modelo con el archivo físico de almacenamiento (SQLite). NSManagedObjectContext proporciona un área temporal para trabajar con objetos. Container lo unifica todo en una sola llamada de inicialización.
SQLite (NSSQLiteStoreType) es el almacenamiento estándar usado en la mayoría de aplicaciones. Los datos se guardan en un único archivo .sqlite con soporte de transacciones ACID. Binary (NSBinaryStoreType) es un almacenamiento en formato binario para conjuntos de datos pequeños (hasta unos cientos de objetos). In-Memory (NSInMemoryStoreType) es un almacenamiento temporal en RAM sin persistencia en disco, usado para pruebas y caché.
| Tipo de almacenamiento | Formato | Rendimiento | Cuándo usarlo |
|---|---|---|---|
| SQLite | .sqlite | Alto | Opción estándar para producción |
| Binary | .binary | Medio | Conjuntos de datos pequeños |
| In-Memory | RAM | Máximo | Pruebas, caché, datos temporales |
| CloudKit | iCloud | Depende de la red | Sincronización entre dispositivos |
El tipo de almacenamiento se define con una sola línea al inicializar NSPersistentStoreDescription. El desarrollador puede cambiar de SQLite a In-Memory para pruebas unitarias o a CloudKit para sincronización con iCloud sin modificar el código de manipulación de objetos — Core Data abstrae las diferencias entre tipos de almacenamiento mediante una API de contexto unificada.
NSManagedObject es la clase base para todos los objetos de Core Data, que representa un único registro de entidad. Cada managed object tiene un NSManagedObjectID único (identificador persistente), está vinculado a un contexto y rastrea sus cambios mediante KVO (Key-Value Observing). Los desarrolladores crean subclases de NSManagedObject para definir propiedades tipadas de la entidad.
NSManagedObjectContext es el componente central de Core Data que proporciona un área de trabajo para todas las operaciones con objetos. El contexto rastrea altas, bajas y modificaciones (change tracking), admite deshacer operaciones mediante undoManager y fusiona automáticamente cambios de otros contextos al recibir notificaciones de guardado.
La regla de colas privadas: NSManagedObjectContext se crea con .privateQueueConcurrencyType o .mainQueueConcurrencyType. El contexto principal está vinculado al hilo principal de la UI, mientras que los contextos privados se ejecutan en colas de fondo. Cada contexto debe usarse solo en su propia cola — acceder a un managed object desde otro hilo provoca un crash. parentContext permite organizar una jerarquía de contextos para escrituras asíncronas.
struct CoreDataStack {
let container: NSPersistentContainer
init(name: String) {
container = NSPersistentContainer(name: name)
container.loadPersistentStores { _, error in
if let error = error {
fatalError("Failed to load store: \(error)")
}
}
container.viewContext.automaticallyMergesChangesFromParent = true
}
func backgroundContext() -> NSManagedObjectContext {
let context = container.newBackgroundContext()
context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
return context
}
}
NSPersistentContainer crea automáticamente viewContext (main queue) y proporciona newBackgroundContext() para operaciones en segundo plano. Establecer automaticallyMergesChangesFromParent = true hace que viewContext recoja automáticamente los cambios de los contextos en segundo plano cuando se guardan, actualizando la UI sin necesidad de volver a consultar los datos manualmente.
NSPersistentStoreCoordinator gestiona el almacenamiento físico de datos: abre el archivo, crea las tablas SQLite basadas en el modelo y realiza migraciones cuando el esquema cambia. Al inicializar NSPersistentStoreDescription con NSSQLiteStoreType, Core Data crea un archivo SQLite con un esquema que coincide con el modelo .xcdatamodeld.
Core Data no usa consultas SQL estándar mediante SELECT/INSERT/UPDATE. En su lugar, genera comandos SQL internos basados en el modelo y las consultas realizadas a través de NSFetchRequest. El desarrollador puede activar el registro SQL con el argumento de lanzamiento -com.apple.CoreData.SQLDebug 1 para depurar el rendimiento de las consultas.
Migración ligera (Lightweight Migration) es un proceso automático de actualización del esquema SQLite al añadir nuevos atributos, cambiar flags optional/required o renombrar con renamingID. Se requiere migración pesada para cambios radicales del esquema como fusionar o dividir entidades, y se realiza mediante un NSMigrationManager personalizado.
let description = NSPersistentStoreDescription()
description.url = FileManager.default
.urls(for: .documentDirectory, in: .userDomainMask)
.first?
.appendingPathComponent("Model.sqlite")
description.setOption(true as NSNumber,
forKey: NSMigratePersistentStoresAutomaticallyOption)
description.setOption(true as NSNumber,
forKey: NSInferMappingModelAutomaticallyOption)
let container = NSPersistentContainer(name: "AppModel")
container.persistentStoreDescriptions = [description]
container.loadPersistentStores { _, error in
if let error = error { print("Migration error: \(error)") }
}
Configurar la migración automática mediante NSMigratePersistentStoresAutomaticallyOption y NSInferMappingModelAutomaticallyOption permite a Core Data actualizar de forma independiente el archivo SQLite al añadir atributos o entidades en una nueva versión del modelo. Si la migración no es posible, el store coordinator lanza un error con la descripción del motivo — el desarrollador debe implementar entonces una migración personalizada mediante NSMigrationManager.
NSFetchRequest es la herramienta principal para recuperar objetos de Core Data. Una solicitud contiene el nombre de la entidad, el predicado (filtro), los criterios de ordenación, el límite y el desplazamiento. El resultado se devuelve como un array de NSManagedObject o subclases tipadas. NSPredicate admite condiciones complejas con AND, OR, IN, LIKE y subconsultas.
NSBatchDeleteRequest es una forma eficiente de eliminar objetos en lote sin cargar cada uno en memoria. La solicitud se ejecuta a nivel de SQLite, omitiendo el managed object context, y solo actualiza el contexto al finalizar. Existen solicitudes batch similares para actualizar (NSBatchUpdateRequest) e insertar (NSBatchInsertRequest).
CRUD (Create, Read, Update, Delete) en Core Data se realiza mediante métodos del contexto: insert, fetch, save y delete. Todos los cambios son temporales hasta que se llama a context.save() — este método guarda los cambios en el almacenamiento persistente SQLite. Si hay error al guardar, el contexto permanece en su estado modificado para un reintento.
let context = container.viewContext
// Crear
let user = User(context: context)
user.id = 42
user.name = "Alice"
// Leer
let request = User.fetchRequest()
request.predicate = NSPredicate(format: "name CONTAINS %@", "Ali")
request.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
let results = try context.fetch(request)
// Actualizar
results.first?.name = "Alice Updated"
// Eliminar
if let first = results.first { context.delete(first) }
// Guardar
try context.save()
Guardar el contexto (context.save()) es una operación crítica. Si no se llama a save, todos los cambios permanecen solo en memoria. El contexto rastrea el estado hasChanges, que se puede comprobar antes de guardar. Para operaciones en segundo plano, use newBackgroundContext con su propio guardado, y para la UI, use viewContext con guardado automático por temporizador o al pasar la aplicación a segundo plano.
Primera práctica — use NSPersistentCloudKitContainer para sincronizar datos entre dispositivos del usuario a través de iCloud. La sincronización en la nube se activa añadiendo la opción CloudKit a la descripción del persistent store. Core Data gestiona automáticamente los conflictos de sincronización y fusiona los cambios de otros dispositivos.
Segunda práctica — evite fetchRequest sin predicado en tablas grandes. Cada fetch incondicional carga todos los objetos de la entidad en memoria, lo que provoca un alto consumo de RAM y ralentiza la UI. Use siempre predicados y límites. Para paginación, use fetchLimit y fetchOffset en NSFetchRequest.
Tercera práctica — configure mergePolicy para resolver conflictos en acceso multihilo. NSMergeByPropertyObjectTrumpMergePolicy actualiza las propiedades en conflicto desde el último contexto guardado. NSRollbackMergePolicy descarta los cambios del contexto actual ante un conflicto. La elección de la política depende de la lógica de negocio de la aplicación.
Cuarta práctica — use NSFetchedResultsController para integración con tablas y colecciones. Se suscribe automáticamente a las notificaciones NSManagedObjectContextDidSave, carga solo los objetos necesarios (faulting) y notifica al delegado sobre inserciones, eliminaciones y movimientos con los index paths correspondientes para la animación de UITableView.
Faulting es el mecanismo de carga perezosa de Core Data. Un managed object devuelto por una fetch request está en estado fault — sus atributos no están completamente cargados, solo el identificador. La carga completa (fire fault) ocurre al primer acceso a cualquier atributo. Relationship prefetching (setRelationshipKeyPathsForPrefetching) carga objetos relacionados por adelantado, evitando consultas N+1.
extension UserRepository {
func fetchUsersWithPosts() throws -> [User] {
let request = User.fetchRequest()
request.predicate = NSPredicate(format: "isActive == YES")
request.relationshipKeyPathsForPrefetching = ["posts"]
request.returnsObjectsAsFaults = false
request.fetchBatchSize = 20
let context = container.viewContext
return try context.fetch(request)
}
}
fetchBatchSize = 20 hace que Core Data cargue datos en lotes de 20 objetos (para mostrar en pantalla), sin cargar toda la tabla de una vez. El flag returnsObjectsAsFaults = false garantiza que todos los atributos del usuario se carguen inmediatamente, lo que es útil para visualización directa. El prefetching de la relación “posts” evita consultas separadas para cada usuario al acceder a las publicaciones.
Preguntas frecuentes
No, Core Data es un framework de gestión de grafos de objetos. Proporciona una API para trabajar con objetos, rastrear cambios y persistirlos. La base de datos bajo el capó de Core Data (SQLite por defecto) no debe confundirse con el propio framework. Core Data es un ORM, no un SGBD.
Sí, Core Data admite tres tipos de almacenamiento: SQLite, Binary e In-Memory. El tipo de almacenamiento se define mediante NSPersistentStoreDescription. El almacenamiento In-Memory no persiste datos en disco y es adecuado para pruebas unitarias. El almacenamiento Binary es un formato heredado para conjuntos de objetos compactos.
Para migración ligera, active NSMigratePersistentStoresAutomaticallyOption y NSInferMappingModelAutomaticallyOption. Para cambios complejos, cree un Mapping Model (.xcmappingmodel) mediante Xcode. El almacenamiento CloudKit (NSPersistentCloudKitContainer) admite migraciones automáticamente al sincronizar el esquema con el servidor iCloud.
SwiftData es un nuevo framework de Apple (iOS 17+) construido sobre Core Data usando Swift Macros y Swift Concurrency. SwiftData tiene una sintaxis más simple: las entidades se describen con el macro @Model, el contexto con @Environment(\.modelContext). Bajo el capó, SwiftData usa el mismo stack de Core Data y SQLite.
Active el argumento de lanzamiento -com.apple.CoreData.SQLDebug 1 — Core Data mostrará todas las consultas SQL y su duración en la consola de Xcode. Para perfilado, use Instruments con la plantilla Core Data, que muestra el número de fault requests, tiempos de carga de objetos y duración del guardado del contexto.
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