Core Data — cos'è, modello dati e come funziona

Autore: IT Sectr Pubblicato: 2026-05-04 Tempo di lettura: 8 min

Core Data è un framework di gestione dati di Apple che fornisce mapping oggetto-relazionale per iOS, macOS, tvOS e watchOS. Automatizza il salvataggio, il recupero e il filtraggio degli oggetti nell'applicazione, funzionando su SQLite, XML o archiviazione binaria. Secondo la Apple Core Data Documentation, il framework utilizza i concetti di Managed Object Context e NSPersistentContainer per gestire lo stack di persistenza.

Punti chiave

  • Core Data — framework Apple per la gestione oggetto-relazionale dei dati nelle applicazioni.
  • NSManagedObjectModel — descrizione dello schema dati: Entity, Attributes e Relationships.
  • NSManagedObject — oggetto corrispondente a un record nell'archivio Core Data.
  • NSManagedObjectContext — area di lavoro per creare, leggere e salvare oggetti.
  • NSPersistentContainer — stack unificato che combina modello, contesto e coordinatore di archiviazione.

Cos'è Core Data e il suo ruolo in iOS

Core Data è un framework di gestione del grafico oggetti e della persistenza che fa parte di Cocoa Touch. Contrariamente a un'idea sbagliata comune, Core Data non è un database, ma un layer di gestione oggetti che può utilizzare SQLite come uno dei suoi archivi. Il compito principale di Core Data è tracciare le modifiche degli oggetti, gestire il loro ciclo di vita e sincronizzare lo stato con il disco.

Il framework fornisce un grafico oggetti in cui ogni Managed Object viene monitorato dal contesto per rilevare le modifiche. Al momento del salvataggio, tutti gli oggetti modificati, aggiunti ed eliminati vengono impegnati nell'archivio persistente in un'unica transazione. Ciò elimina la necessità per lo sviluppatore di scrivere query SQL e gestire manualmente le transazioni.

Secondo le statistiche del Swift Developer Survey (2025), Core Data viene utilizzato nel 52% delle applicazioni iOS che lavorano con dati locali. Nonostante l'emergere di alternative moderne (SwiftData, Realm), Core Data rimane il framework principale nei progetti Apple esistenti grazie alla sua maturità e alla profonda integrazione con il sistema.

Utilizza Core Data per progetti con un modello dati di complessità media, dove sono necessarie relazioni tra oggetti, annullamento delle modifiche e caching automatico attraverso il meccanismo di faulting.

L'architettura di Core Data è costruita attorno al concetto di Managed Object Context — un'area di lavoro che traccia tutte le modifiche degli oggetti. Il contesto supporta annulla/ripeti tramite l'NSUndoManager integrato, consentendo di implementare bozze e annullamento di azioni senza salvare manualmente snapshot dello stato. Quando viene chiamato save(), il contesto impegna tutte le modifiche in un'unica transazione nell'archivio persistente, garantendo atomicità e consistenza dei dati.

Modello dati: Entity, Attributes, Relationships

Il modello dati di Core Data viene definito nel file .xcdatamodeld — l'editor visivo di Xcode in cui vengono descritte tutte le Entity, i loro attributi e le relazioni. In fase di compilazione, il modello viene serializzato in .momd e caricato tramite NSManagedObjectModel.

Entity e Attributes

Entity è una descrizione di tipo dati, simile a una tabella in SQL. Ogni Entity contiene un insieme di Attributes — campi nominati con un tipo di dati (String, Integer, Date, Boolean, Data). A differenza di Room, Core Data richiede una selezione esplicita del tipo per ogni attributo tramite l'editor del modello.

Relationships

Relationship è una connessione tra Entity, simile a una chiave esterna in SQL. Core Data supporta tutti i tipi di relazione: uno-a-uno, uno-a-molti e molti-a-molti. Per ogni relazione viene configurata una Delete Rule (Cascade, Nullify, Deny) — il comportamento in caso di eliminazione dell'oggetto correlato.

Delete RuleComportamento in caso di eliminazioneEsempio di utilizzo
CascadeElimina tutti gli oggetti correlatiEliminare un ordine insieme ai suoi articoli
NullifyAnnulla la relazione inversaEliminare un autore senza eliminare i libri
DenyBlocca l'eliminazione se esistono oggetti correlatiProteggere dall'eliminazione di una categoria con prodotti

Scegliere una Delete Rule è fondamentale per l'integrità dei dati: Cascade senza verifica può eliminare un terzo del database, mentre Deny può bloccare l'operazione con un errore poco chiaro. Nel codice di produzione, si consiglia Nullify con gestione manuale dei record orfani.

Nell'editor di modelli di Xcode, lo sviluppatore può definire non solo Entity e attributi, ma anche constraints (vincoli di unicità), indici per accelerare le query e valori predefiniti per gli attributi. Tutte le modifiche al modello vengono compilate in un file .momd, che viene caricato durante l'inizializzazione di NSPersistentContainer. Il versionamento del modello (Model Versioning) consente di mantenere più versioni dello schema ed eseguire la migrazione tra di esse.

Stack Core Data: PersistentContainer e Context

NSPersistentContainer è un unico oggetto che gestisce lo stack Core Data da iOS 10 e macOS 10.12. Incapsula NSManagedObjectModel, NSPersistentStoreCoordinator e NSManagedObjectContext, automatizzando il caricamento del modello e la configurazione dell'archivio. Per le versioni precedenti, lo stack veniva costruito manualmente, ma ora non è più raccomandato.

swift
let container = NSPersistentContainer(name: "DataModel")
container.loadPersistentStores { _, error in
    if let error { fatalError("Core Data load failed: \(error)") }
}
let context = container.viewContext

viewContext è il contesto principale legato al thread principale. Tutte le letture e gli aggiornamenti dell'interfaccia vengono eseguiti tramite esso. Per le prestazioni, si consiglia di eseguire la scrittura dei dati in un contesto figlio in background con successiva sincronizzazione.

NSPersistentStoreCoordinator

Il coordinatore NSPersistentStoreCoordinator collega il modello all'archiviazione fisica su disco. Core Data supporta diversi tipi di archivio: SQLite (raccomandato), Binary e In-Memory. L'archivio SQLite supporta migrazioni, backup incrementale e resistenza agli arresti anomali durante le operazioni di scrittura.

NSFetchRequest e lavoro con i dati

NSFetchRequest è un oggetto che descrive una query all'archivio Core Data. Contiene il nome dell'Entity, il predicato di filtro, i descrittori di ordinamento e le impostazioni di fetch. La query viene eseguita tramite context.fetch(), che restituisce un array di NSManagedObject.

swift
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 supporta condizioni complesse: LIKE, IN, BETWEEN, CONTAINS[c] (senza distinzione maiuscole/minuscole), SUBQUERY per query annidate su Entity correlate. Core Data supporta anche NSFetchedResultsController — una classe per il caricamento reattivo dei dati in UITableView, che traccia automaticamente le modifiche e aggiorna la tabella con sezioni animate.

Core Data in ambiente multi-thread

Lavorare con Core Data in un'applicazione multi-thread richiede il rigoroso rispetto delle regole: NSManagedObject non può essere passato direttamente tra thread. Ogni thread (o coda) deve utilizzare il proprio contesto. L'approccio principale consiste nel creare un NSManagedObjectContext figlio con una coda privata (NSPrivateQueueConcurrencyType) per la scrittura e viewContext per la lettura.

Il contesto figlio salva nel genitore, e poi il genitore salva nell'archivio su disco. Ciò garantisce che le modifiche non blocchino il thread principale e che l'interfaccia utente veda sempre uno stato coerente tramite mergeChanges o l'aggiornamento automatico di viewContext al salvataggio.

Core Data utilizza il faulting — un meccanismo di caricamento differito per gli oggetti correlati. Quando si recupera un User senza richiedere i suoi indirizzi, gli oggetti Address correlati non vengono caricati finché non vengono acceduti tramite notazione puntata. Il faulting risparmia memoria e accelera il caricamento, ma può causare accessi imprevisti al disco sul thread principale se l'accesso non viene controllato nei contesti in background.

Per un multi-threading efficiente, utilizza NSBatchInsertRequest e NSBatchDeleteRequest per inserimenti ed eliminazioni in massa senza caricare gli oggetti in memoria — questo è fondamentale per la sincronizzazione dei dati con il server.

Le operazioni batch vengono eseguite direttamente a livello di NSPersistentStoreCoordinator, bypassando il contesto e il grafico oggetti. Ciò consente di inserire 10.000 record in millisecondi senza creare 10.000 istanze di NSManagedObject in memoria. Dopo l'esecuzione di una richiesta batch, il contesto deve essere aggiornato tramite mergeChangesFromContextDidSaveNotification in modo che l'interfaccia utente rifletta i nuovi dati. Apple raccomanda le operazioni batch per il caricamento iniziale dei dati e la sincronizzazione notturna con il server.

Per il tracciamento delle modifiche in Core Data, viene utilizzato NSPersistentHistoryTracking — un meccanismo che registra ogni transazione (inserimento, aggiornamento, eliminazione) in una cronologia separata. L'attivazione del tracciamento della cronologia consente di sincronizzare i dati tra diversi processi e applicazioni che lavorano con lo stesso file SQLite, ad esempio tra l'applicazione principale e una Notification Service Extension. L'attivazione avviene tramite NSPersistentStoreDescription con il flag persistentHistoryTrackingKey, e la lettura tramite NSPersistentHistoryChangeRequest con filtro per data e tipo di transazione.

Per il debug e il profiling delle prestazioni di Core Data, viene utilizzato lo strumento Core Data Profiler della suite Instruments in Xcode su macOS. Mostra tutte le operazioni di fetch, inserimento, eliminazione e salvataggio con la durata di ogni operazione e il numero di oggetti caricati in tabelle e grafici della timeline. Lo sviluppatore può identificare le aree problematiche: fetch multipli della stessa query (mancanza di caching), perdite di oggetti fault durante lo scorrimento della tabella o blocco del thread principale a causa del caricamento sincrono di entità correlate. Si consiglia di eseguire il profiling su un dispositivo reale e non su un simulatore, poiché le prestazioni del simulatore non riflettono il comportamento reale dell'applicazione su un iPhone o iPad.

Domande frequenti

Qual è la differenza tra Core Data e SQLite?

Core Data non è un database, ma un layer di gestione oggetti che può utilizzare SQLite come archivio. A differenza di SQLite puro, Core Data traccia le modifiche degli oggetti, gestisce l'annullamento e fornisce un grafico oggetti con faulting e caching. SQLite offre più controllo sulle query, ma richiede di scrivere SQL e gestire manualmente le transazioni.

Come eseguire la migrazione dello schema di Core Data?

Core Data supporta la migrazione leggera (Lightweight Migration) per modifiche non distruttive: aggiunta di un attributo, ridenominazione, impostazione di un valore predefinito. Per modifiche complesse, viene creato un Mapping Model. La migrazione leggera viene attivata dal flag shouldMigrateAutomatically in NSPersistentStoreDescription.

Si può usare Core Data con SwiftUI?

Sì, Core Data si integra con SwiftUI tramite il wrapper @FetchRequest per le query e @ObservedObject per la sottoscrizione alle modifiche. SwiftUI aggiorna automaticamente la View quando un ManagedObject cambia, rendendo Core Data e SwiftUI uno stack compatibile per la gestione dello stato.

Cos'è un fault in Core Data?

Un fault è un segnaposto leggero nel grafico di Core Data che non contiene i dati dell'oggetto correlato. Quando viene impostato un fault (tramite refreshObject:), i dati vengono scaricati dalla memoria. Quando si accede a una proprietà, il fault si riempie automaticamente con i dati dall'archivio — questo è un meccanismo di caricamento differito che ottimizza l'uso della memoria.

Come testare il codice Core Data?

Per i test, utilizza il tipo di archivio In-Memory: NSPersistentStoreDescription con NSInMemoryStoreType. Il contenitore viene creato con il modello dal bundle di test. Dopo ogni test, elimina tutti gli oggetti o ricrea il contenitore — questo garantisce l'isolamento dei casi di test gli uni dagli altri.

Riepilogo

  • Core Data è un framework di gestione del grafico oggetti che utilizza SQLite come archivio predefinito.
  • NSManagedObjectModel descrive lo schema: Entity, Attributes, Relationships e Delete Rules.
  • NSPersistentContainer combina modello, coordinatore e viewContext in uno stack unificato.
  • NSFetchRequest con NSPredicate e NSSortDescriptor forma query flessibili all'archivio.
  • Il multi-threading richiede contesti separati: un contesto figlio per la scrittura e viewContext per la lettura.
  • Faulting rimanda il caricamento degli oggetti correlati fino al primo accesso, risparmiando memoria.
  • Lightweight Migration gestisce automaticamente le modifiche dello schema non distruttive senza perdita di dati.

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche