avdlee/core-data-expert

Guía experta de Core Data (iOS/macOS): configuración del stack, solicitudes de recuperación y NSFetchedResultsController, guardado y conflictos de fusión, hilos y Swift Concurrency, operaciones por lotes e historial persistente, migraciones, rendimiento y sincronización con NSPersistentCloudKitContainer/CloudKit.

¿Qué es core-data-expert?

Este skill proporciona orientación experta sobre Core Data, el framework de persistencia de Apple para iOS y macOS. Cubre desde la configuración básica del stack de Core Data (NSManagedObjectModel, NSPersistentStoreCoordinator, NSManagedObjectContext) hasta temas avanzados como solicitudes de recuperación optimizadas con NSFetchedResultsController, gestión de conflictos de fusión al guardar, y estrategias de concurrencia utilizando tanto hilos tradicionales como Swift Concurrency (async/await). También aborda operaciones por lotes (NSBatchDeleteRequest, NSBatchUpdateRequest) y el historial persistente para sincronizar cambios entre contextos, migraciones de esquemas de datos (ligeras, pesadas, personalizadas), técnicas de rendimiento como la carga diferida y la descarga en caché, y la integración con NSPersistentCloudKitContainer para sincronización con CloudKit. Es compatible con proyectos de Xcode para iOS, macOS, watchOS y tvOS, y su documentación detallada permite a los desarrolladores resolver problemas complejos de persistencia de datos de manera eficiente y robusta.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/avdlee/core-data-agent-skill/tree/main/skills/core-data-expert

Installed? Explore more Productividad y colaboración skills: steipete/gemini, steipete/gh-issues, steipete/skill-creator · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

¿Qué hace core-data-expert?

Guía experta de Core Data (iOS/macOS): configuración del stack, solicitudes de recuperación y NSFetchedResultsController, guardado y conflictos de fusión, hilos y Swift Concurrency, operaciones por lote e historial persistente, migraciones, rendimiento y sincronización con NSPersistentCloudKitContainer/CloudKit.

Configuración del Stack

Stack básico

import CoreData

class CoreDataStack {
    static let shared = CoreDataStack()
    
    lazy var persistentContainer: NSPersistentContainer = {
        let container = NSPersistentContainer(name: "Modelo")
        container.loadPersistentStores { storeDescription, error in
            if let error = error as NSError? {
                fatalError("Error al cargar la tienda persistente: \(error)")
            }
        }
        return container
    }()
    
    var context: NSManagedObjectContext {
        persistentContainer.viewContext
    }
    
    func saveContext() {
        let context = persistentContainer.viewContext
        if context.hasChanges {
            do {
                try context.save()
            } catch {
                let nserror = error as NSError
                fatalError("Error al guardar el contexto: \(nserror)")
            }
        }
    }
}

Stack con CloudKit

lazy var persistentContainer: NSPersistentCloudKitContainer = {
    let container = NSPersistentCloudKitContainer(name: "Modelo")
    container.loadPersistentStores { storeDescription, error in
        if let error = error as NSError? {
            fatalError("Error al cargar la tienda: \(error)")
        }
    }
    container.viewContext.automaticallyMergesChangesFromParent = true
    return container
}()

Solicitudes de Recuperación (Fetch Requests) y NSFetchedResultsController

Solicitud básica

let request: NSFetchRequest<Entidad> = Entidad.fetchRequest()
request.predicate = NSPredicate(format: "atributo == %@", valor)
request.sortDescriptors = [NSSortDescriptor(key: "fecha", ascending: false)]

NSFetchedResultsController

let fetchRequest: NSFetchRequest<Entidad> = Entidad.fetchRequest()
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "nombre", ascending: true)]

let controller = NSFetchedResultsController(
    fetchRequest: fetchRequest,
    managedObjectContext: context,
    sectionNameKeyPath: nil,
    cacheName: nil
)
controller.delegate = self

try controller.performFetch()

Guardado y Conflictos de Fusión

Estrategias de fusión

context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
// O NSMergeByPropertyStoreTrumpMergePolicy
// O NSOverwriteMergePolicy
// O NSRollbackMergePolicy

Guardado en segundo plano

let privateContext = persistentContainer.newBackgroundContext()
privateContext.perform {
    // Realizar operaciones aquí
    do {
        try privateContext.save()
    } catch {
        print("Error al guardar: \(error)")
    }
}

Hilos y Swift Concurrency

Uso de async/await

func fetchEntidadesAsync() async throws -> [Entidad] {
    let context = persistentContainer.newBackgroundContext()
    return try await context.perform {
        let request: NSFetchRequest<Entidad> = Entidad.fetchRequest()
        return try context.fetch(request)
    }
}

Contextos hijo

let childContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
childContext.parent = parentContext

Operaciones por Lote e Historial Persistente

Eliminación por lote

let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest as! NSFetchRequest<NSFetchRequestResult>)
try context.execute(deleteRequest)

Historial persistente

let historyToken: NSPersistentHistoryToken?
let fetchHistoryRequest = NSPersistentHistoryChangeRequest.fetchHistory(after: historyToken)
let result = try context.execute(fetchHistoryRequest) as? NSPersistentHistoryResult

Migraciones

Migración ligera

let options = [NSMigratePersistentStoresAutomaticallyOption: true,
               NSInferMappingModelAutomaticallyOption: true]
container.persistentStoreDescriptions.forEach { description in
    description.setOption(true, forKey: NSMigratePersistentStoresAutomaticallyOption)
    description.setOption(true, forKey: NSInferMappingModelAutomaticallyOption)
}

Migración personalizada

  1. Crear un nuevo modelo de datos
  2. Crear un modelo de mapeo
  3. Implementar NSEntityMigrationPolicy

Rendimiento

  • Lazy loading: Usar relaciones de manera eficiente
  • Batch fetching: fetchBatchSize para conjuntos grandes
  • Faulting: setRelationshipKeyPaths(forPrefetching:)
  • Caché: Usar NSFetchedResultsController con caché

Batch fetching

request.fetchBatchSize = 20

Sincronización con NSPersistentCloudKitContainer

Configuración básica CloudKit

let container = NSPersistentCloudKitContainer(name: "Modelo")
container.loadPersistentStores { _, error in
    if let error = error {
        fatalError("Error: \(error)")
    }
}
container.viewContext.automaticallyMergesChangesFromParent = true

Notas importantes sobre CloudKit

  • Asegurar que el modelo de datos tenga un NSPersistentCloudKitContainer como tipo de contenedor
  • Crear un esquema de CloudKit en el panel de CloudKit Dashboard
  • Manejar errores de red y conflictos
  • Probar con cuentas de iCloud reales

Skills relacionados