Core Data — conceptos clave, NSManagedObject y arquitectura

Autor: IT Sectr Publicado: 2026-03-11 Tiempo de lectura: 11 min

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 ORM para iOS/macOS que gestiona un grafo de objetos y los persiste en un almacenamiento.
  • NSManagedObjectModel es el esquema de datos que describe entidades, atributos y relaciones en un modelo de Core Data.
  • NSManagedObjectContext es un área de trabajo para crear, leer, actualizar y eliminar objetos con seguimiento de cambios.
  • NSPersistentContainer es un punto de entrada unificado que encapsula el modelo, el contexto y el almacenamiento en iOS 10+.
  • NSFetchedResultsController integra Core Data con UITableView/UICollectionView con actualización automática ante cambios.

¿Qué es Core Data?

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.

Core Data no es una base de datos

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.

Arquitectura de Core Data: stacks y componentes

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.

Tipos de almacenamiento de Core Data

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 almacenamientoFormatoRendimientoCuándo usarlo
SQLite.sqliteAltoOpción estándar para producción
Binary.binaryMedioConjuntos de datos pequeños
In-MemoryRAMMáximoPruebas, caché, datos temporales
CloudKitiCloudDepende de la redSincronizació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 y NSManagedObjectContext

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.

Seguridad de hilos en contextos

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.

swift
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.

Persistent Store y SQLite

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.

Migraciones de Core Data

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.

swift
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.

Core Data en la práctica: código y ejemplos

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).

Ejemplo de operaciones CRUD

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.

swift
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.

Mejores prácticas de Core Data

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.

Rendimiento: Prefetching y Faulting

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.

swift
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

¿Es Core Data una base de datos?

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.

¿Se puede usar Core Data sin SQLite?

, 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.

¿Cómo migrar Core Data a una nueva versión del modelo?

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.

¿En qué se diferencia Core Data de SwiftData?

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.

¿Cómo depurar consultas lentas de Core Data?

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

  • Core Data es un framework de gestión de grafos de objetos y persistencia para iOS y macOS, que usa SQLite como almacenamiento predeterminado.
  • El stack de Core Data incluye NSManagedObjectModel, NSPersistentStoreCoordinator, NSManagedObjectContext y NSPersistentContainer para configuración unificada.
  • NSManagedObjectContext es un área de trabajo con seguimiento de cambios, soporte de deshacer y fusión automática desde contextos en segundo plano.
  • NSFetchRequest con NSPredicate y prefetching de relaciones es la herramienta principal de consulta, optimizada mediante batch size y faulting.
  • Lightweight Migration actualiza automáticamente el esquema SQLite al añadir atributos y entidades en una nueva versión del modelo.
  • NSPersistentCloudKitContainer añade sincronización iCloud entre dispositivos del usuario con resolución automática de conflictos.
  • Recomendación — use Core Data para aplicaciones iOS con modelos de objetos jerárquicos; para almacenamiento local simple, considere GRDB o SwiftData.

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.

Discutir el proyecto

Lea también