Core Data este un framework de gestionare a datelor de la Apple, care oferă mapare obiect-relațională pentru iOS, macOS, tvOS și watchOS. Automatizează salvarea, extragerea și filtrarea obiectelor în aplicație, funcționând pe SQLite, XML sau stocare binară. Conform Apple Core Data Documentation, framework-ul utilizează conceptele Managed Object Context și NSPersistentContainer pentru gestionarea stivei de persistență.
Principalele
Core Data — este un framework de gestionare a grafului de obiecte și a persistenței, care face parte din Cocoa Touch. Contrar concepției greșite răspândite, Core Data nu este o bază de date, ci un strat de gestionare a obiectelor care poate utiliza SQLite ca unul dintre depozite. Sarcina principală a Core Data este de a urmări modificările obiectelor, de a gestiona ciclul lor de viață și de a sincroniza starea cu discul.
Framework-ul oferă un graf de obiecte, în care fiecare Managed Object este urmărit de context pentru modificări. La salvarea contextului, toate obiectele modificate, adăugate și șterse sunt confirmate în stocarea persistentă printr-o singură tranzacție. Acest lucru eliberează dezvoltatorul de scrierea interogărilor SQL și gestionarea manuală a tranzacțiilor.
Conform statisticilor Swift Developer Survey (2025), Core Data este utilizat în 52% din aplicațiile iOS care lucrează cu date locale. În ciuda apariției alternativelor moderne (SwiftData, Realm), Core Data rămâne principalul framework în proiectele Apple existente datorită maturității și integrării profunde cu sistemul.
Utilizați Core Data pentru proiecte cu un model de date de complexitate medie, unde sunt necesare relații între obiecte, anularea modificărilor și cache automat prin mecanismul faulting.
Arhitectura Core Data este construită în jurul conceptului de Managed Object Context — un spațiu de lucru care urmărește toate modificările obiectelor. Contextul suportă anularea (undo/redo) prin NSUndoManager încorporat, ceea ce permite implementarea ciornelor și anularea acțiunilor fără salvarea manuală a instantaneelor de stare. La apelarea save(), contextul confirmă toate modificările printr-o singură tranzacție în stocarea persistentă, garantând atomicitatea și consistența datelor.
Modelul de date Core Data este definit în fișierul .xcdatamodeld — editorul vizual Xcode, unde sunt descrise toate Entitățile, atributele și relațiile lor. La compilare, modelul este serializat în .momd și încărcat prin NSManagedObjectModel.
Entity — este o descriere a tipului de date, similară unui tabel în SQL. Fiecare Entity conține un set de Attributes — câmpuri denumite cu un tip de date (String, Integer, Date, Boolean, Data). Spre deosebire de Room, Core Data necesită alegerea explicită a tipului pentru fiecare atribut prin editorul de model.
Relationship — relație între Entități, similară unei chei externe în SQL. Core Data suportă toate tipurile de relații: unu-la-unu, unu-la-mulți și mulți-la-mulți. Pentru fiecare relație se configurează Delete Rule (Cascade, Nullify, Deny) — comportamentul la ștergerea obiectului asociat.
| Delete Rule | Comportament la ștergere | Exemplu de utilizare |
|---|---|---|
| Cascade | Șterge toate obiectele asociate | Ștergerea comenzii împreună cu pozițiile |
| Nullify | Anulează relația inversă | Ștergerea autorului fără ștergerea cărților |
| Deny | Blochează ștergerea dacă există obiecte asociate | Protecția împotriva ștergerii categoriei cu produse |
Alegerea Delete Rule este critică pentru integritatea datelor: Cascade fără verificare poate șterge o treime din bază, iar Deny poate bloca operația cu o eroare de neînțeles. În codul de producție, se recomandă Nullify cu procesarea manuală a înregistrărilor orfane.
În editorul de model Xcode, dezvoltatorul poate seta nu doar Entity și atribute, ci și constraints (restricții de unicitate), indecși pentru accelerarea interogărilor și default values pentru atribute. Toate modificările modelului sunt compilate în fișierul .momd, care este încărcat la inițializarea NSPersistentContainer. Versionarea modelului (Model Versioning) permite menținerea mai multor versiuni ale schemei și efectuarea migrării între ele.
NSPersistentContainer — un obiect unitar care gestionează stiva Core Data de la iOS 10 și macOS 10.12. Acesta încapsulează NSManagedObjectModel, NSPersistentStoreCoordinator și NSManagedObjectContext, automatizând încărcarea modelului și configurarea stocării. Pentru versiunile mai vechi, stiva se construia manual, dar acum acest lucru nu este recomandat.
let container = NSPersistentContainer(name: "DataModel")
container.loadPersistentStores { _, error in
if let error { fatalError("Core Data load failed: \(error)") }
}
let context = container.viewContext
viewContext — contextul principal legat de firul principal. Toate citirile și actualizările UI se efectuează prin acesta. Scrierea datelor pentru performanță se recomandă a fi efectuată într-un context copil cu coadă privată și sincronizare ulterioară.
Coordonatorul NSPersistentStoreCoordinator leagă modelul de stocarea fizică pe disc. Core Data suportă mai multe tipuri de stocări: SQLite (recomandat), Binary și In-Memory. Stocarea SQLite suportă migrări, backup incremental și rezistență la erori în timpul procesului de scriere.
NSFetchRequest — un obiect care descrie o interogare către stocarea Core Data. Conține numele Entității, predicatul de filtrare, sortarea și setările de preluare. Interogarea se execută prin context.fetch(), care returnează 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 suportă condiții complexe: LIKE, IN, BETWEEN, CONTAINS[c] (fără diferențiere între majuscule și minuscule), SUBQUERY pentru interogări imbricate pe Entități asociate. Core Data suportă de asemenea NSFetchedResultsController — o clasă pentru încărcarea reactivă a datelor în UITableView, care urmărește automat modificările și actualizează tabelul cu secțiuni animate.
Lucrul cu Core Data într-o aplicație multi-thread necesită respectarea strictă a regulilor: NSManagedObject nu poate fi transmis direct între fire. Fiecare fir (sau coadă) trebuie să utilizeze propriul context. Abordarea principală — crearea unui NSManagedObjectContext copil cu o coadă privată (NSPrivateQueueConcurrencyType) pentru scriere și viewContext pentru citire.
Contextul copil se salvează în părinte, iar apoi părintele — în stocarea pe disc. Aceasta garantează că modificările nu blochează firul principal și că UI vede întotdeauna o stare consistentă prin mergeChanges sau actualizarea automată a viewContext la salvare.
Core Data utilizează faulting — un mecanism de încărcare întârziată a obiectelor asociate. La preluarea User fără a solicita addresses-ul său, Address-urile asociate nu se încarcă până când nu se face o referire la ele prin notația cu punct. Faulting economisește memoria și accelerează încărcarea, dar poate cauza accesări neașteptate la disc pe firul principal dacă accesul nu este controlat în contextele de fundal.
Pentru multi-threading eficient, utilizați NSBatchInsertRequest și NSBatchDeleteRequest pentru inserarea și ștergerea în masă fără încărcarea obiectelor în memorie — acest lucru este critic pentru sincronizarea datelor cu serverul.
Operațiile batch se execută direct la nivelul NSPersistentStoreCoordinator, ocolind contextul și graful de obiecte. Acest lucru permite inserarea a 10.000 de înregistrări în câteva milisecunde fără a crea 10.000 de instanțe NSManagedObject în memorie. După executarea interogării batch, contextul trebuie actualizat prin mergeChangesFromContextDidSaveNotification pentru ca UI să reflecte noile date. Apple recomandă operațiile batch pentru încărcarea inițială a datelor și sincronizarea nocturnă cu serverul.
Pentru urmărirea modificărilor în Core Data se utilizează NSPersistentHistoryTracking — un mecanism care înregistrează fiecare tranzacție (inserare, actualizare, ștergere) într-un istoric separat. Activarea history tracking permite sincronizarea datelor între diferite procese și aplicații care lucrează cu același fișier SQLite, de exemplu între aplicația principală și Notification Service Extension. Activarea se face prin NSPersistentStoreDescription cu flag-ul persistentHistoryTrackingKey, iar citirea — prin NSPersistentHistoryChangeRequest cu filtru după dată și tipul tranzacției.
Pentru depanarea și profilarea performanței Core Data se utilizează instrumentul Core Data Profiler din setul Instruments din Xcode pe macOS. Acesta arată toate operațiile de preluare, inserare, ștergere și salvare cu durata fiecărei operații și numărul de obiecte încărcate în tabele și pe graficele axei temporale. Dezvoltatorul poate identifica zonele problematice: preluări multiple ale aceleiași interogări (lipsa cache-ului), scurgeri de obiecte fault la derularea tabelului sau blocarea firului principal din cauza încărcării sincrone a entităților asociate. Se recomandă efectuarea profilării pe un dispozitiv real, nu pe simulator, deoarece performanța simulatorului nu reflectă comportamentul real al aplicației pe iPhone sau iPad.
Întrebări frecvente
Core Data — nu este o bază de date, ci un strat de gestionare a obiectelor care poate utiliza SQLite ca stocare. Spre deosebire de SQLite direct, Core Data urmărește modificările obiectelor, gestionează anulările și oferă un graf de obiecte cu faulting și cache. SQLite oferă mai mult control asupra interogărilor, dar necesită scrierea SQL și gestionarea manuală a tranzacțiilor.
Core Data suportă migrarea ușoară (Lightweight Migration) pentru modificări nedistructive: adăugarea unui atribut, redenumirea, setarea unei valori implicite. Pentru modificări complexe se creează un Mapping Model. Migrarea ușoară se activează prin flag-ul shouldMigrateAutomatically în NSPersistentStoreDescription.
Da, Core Data se integrează cu SwiftUI prin wrapper-ul @FetchRequest pentru interogări și @ObservedObject pentru abonarea la modificări. SwiftUI actualizează automat View la modificarea ManagedObject, ceea ce face ca Core Data și SwiftUI să fie o stivă compatibilă pentru gestionarea stării.
Fault — este un substituent ușor în graful Core Data, care nu conține datele obiectului asociat. La setarea fault (prin refreshObject:) datele sunt descărcate din memorie. La accesarea proprietății, fault se completează automat cu datele din stocare — acesta este un mecanism de încărcare întârziată care optimizează utilizarea memoriei.
Pentru testare utilizați tipul de stocare In-Memory: NSPersistentStoreDescription cu NSInMemoryStoreType. Containerul se creează cu modelul din pachetul de test. După fiecare test, ștergeți toate obiectele sau recreați containerul — aceasta garantează izolarea cazurilor de test unul de celălalt.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și