Core Data — framework-ul Apple pentru gestionarea grafului de obiecte în aplicațiile iOS și macOS. Acesta asigură persistența datelor, urmărirea modificărilor, anularea operațiilor și integrarea cu UI prin NSFetchedResultsController. Conform documentației Apple Developer (2025), Core Data nu este o bază de date — este un nivel de modelare obiectuală care, în mod implicit, folosește SQLite ca stocare persistentă pentru încărcarea și salvarea obiectelor.
Principalele puncte
Core Data — este un framework de gestionare a grafului de obiecte și persistență, parte a Cocoa Touch SDK de la Apple. Acesta oferă o interfață orientată pe obiecte pentru lucrul cu datele: dezvoltatorul operează cu entități (Entity), atribute și relații (Relationship), iar Core Data transformă aceste obiecte în înregistrări ale unei baze de date relaționale sub capotă.
Core Data a fost prezentat în Mac OS X 10.4 Tiger (2005) pentru macOS și portat în iOS 3.0 (2009). În peste 20 de ani, framework-ul a evoluat de la un simplu nivel de abstractizare peste SQLite la o stivă completă cu suport pentru sincronizare în cloud prin NSPersistentCloudKitContainer, multi-threading prin gestionarea automată a contextelor și încărcare asincronă prin Swift Concurrency.
Conform unui sondaj al dezvoltatorilor iOS de la Slack Community (2025), Core Data este utilizat în 68% din aplicațiile iOS comerciale pentru stocarea locală a datelor. În ciuda criticilor privind complexitatea și multi-stratificarea, framework-ul rămâne standardul pentru aplicațiile Apple datorită integrării strânse cu sistemul, costului zero (încorporat în SDK) și suportului pentru sincronizarea iCloud.
O concepție greșită frecventă — să consideri Core Data o bază de date. Framework-ul nu execută interogări SQL direct și nu este un SGBD. Core Data este un strat de gestionare a obiectelor (object graph management) care poate folosi SQLite, Binary sau In-Memory pentru persistență. Analogie: Core Data este ca un ORM precum Hibernate sau Entity Framework, dar pentru ecosistemul Apple, iar SQLite sub el — ca MySQL sub Hibernate.
Stiva Core Data este formată din patru componente interconectate: NSManagedObjectModel (schema de date), NSPersistentStoreCoordinator (coordonatorul de stocări), NSManagedObjectContext (contextul de lucru) și NSPersistentContainer (containerul unic care le combină pe toate trei din iOS 10). NSPersistentContainer automatizează crearea și configurarea stivei.
Fiecare componentă îndeplinește o funcție strict definită. NSManagedObjectModel încarcă fișierul .xcdatamodeld cu descrierea entităților. NSPersistentStoreCoordinator leagă modelul de fișierul fizic de stocare (SQLite). NSManagedObjectContext oferă o zonă temporară pentru lucrul cu obiectele. Containerul combină totul într-un singur apel de inițializare.
SQLite (NSSQLiteStoreType) — stocarea standard utilizată în majoritatea aplicațiilor. Datele sunt salvate într-un singur fișier .sqlite cu suport pentru tranzacții ACID. Binary (NSBinaryStoreType) — stocare în format binar pentru seturi mici de date (până la câteva sute de obiecte). In-Memory (NSInMemoryStoreType) — stocare temporară în memoria RAM fără salvare pe disc, utilizată pentru teste și cache.
| Tipul stocării | Format | Performanță | Când să folosești |
|---|---|---|---|
| SQLite | .sqlite | Ridicată | Alegerea standard pentru production |
| Binary | .binary | Medie | Seturi mici de date |
| In-Memory | RAM | Maximă | Teste, cache, date temporare |
| CloudKit | iCloud | Depinde de rețea | Sincronizare între dispozitive |
Alegerea stocării se face printr-o singură linie la inițializarea NSPersistentStoreDescription. Dezvoltatorul poate comuta stocarea de la SQLite la In-Memory pentru testele unitare sau la CloudKit pentru sincronizarea iCloud fără a modifica codul de lucru cu obiectele — Core Data abstractizează diferența dintre tipurile de stocări printr-un API unitar al contextului.
NSManagedObject — clasa de bază pentru toate obiectele Core Data, reprezentând o singură înregistrare a unei entități. Fiecare managed object are un NSManagedObjectID unic (identificator persistent), este legat de un context și își urmărește modificările prin KVO (Key-Value Observing). Dezvoltatorul creează subclase ale NSManagedObject pentru a defini proprietăți tipizate ale entității.
NSManagedObjectContext — componenta centrală a Core Data care oferă o zonă de lucru pentru toate operațiile cu obiecte. Contextul urmărește adăugările, ștergerile și modificările obiectelor (change tracking), suportă anularea operațiilor prin undoManager și îmbină automat modificările din alte contexte la primirea notificărilor de salvare.
Regula cozilor private: NSManagedObjectContext se creează cu tipul .privateQueueConcurrencyType sau .mainQueueConcurrencyType. Contextul principal este legat de firul principal UI, contextele private se execută pe cozi de fundal. Fiecare context trebuie folosit doar pe coada sa — accesarea unui managed object dintr-un alt fir de execuție provoacă un crash. parentContext permite organizarea unei ierarhii de contexete pentru scrierea asincronă.
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 creează automat viewContext (main queue) și oferă newBackgroundContext() pentru operații de fundal. Proprietatea automaticallyMergesChangesFromParent = true face ca viewContext să preia automat modificările din contexetele de fundal la salvarea acestora, actualizând UI fără reîncărcarea manuală a datelor.
NSPersistentStoreCoordinator gestionează stocarea fizică a datelor: deschide fișierul, creează tabele SQLite pe baza modelului, execută migrări la modificarea schemei. La inițializarea NSPersistentStoreDescription cu tipul NSSQLiteStoreType, Core Data creează un fișier SQLite cu schema corespunzătoare modelului .xcdatamodeld.
Core Data nu utilizează interogări SQL standard prin SELECT/INSERT/UPDATE. În schimb, generează comenzi SQL interne pe baza modelului și interogărilor prin NSFetchRequest. Dezvoltatorul poate activa logarea SQL prin argumentul de lansare -com.apple.CoreData.SQLDebug 1 pentru depanarea performanței interogărilor.
Migrarea ușoară (Lightweight Migration) — procesul automat de actualizare a schemei SQLite la adăugarea de noi atribute, modificarea optional/required sau redenumirea cu ajutorul renamingID. Migrarea grea este necesară la modificări radicale ale schemei, cum ar fi îmbinarea sau divizarea entităților, și se execută printr-un NSMigrationManager personalizat.
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)") }
}
Configurarea migrării automate prin NSMigratePersistentStoresAutomaticallyOption și NSInferMappingModelAutomaticallyOption permite Core Data să actualizeze independent fișierul SQLite la adăugarea de atribute sau entități în noua versiune a modelului. Dacă migrarea nu este posibilă, store coordinator aruncă o eroare cu descrierea motivului — dezvoltatorul trebuie să implementeze o migrare personalizată prin NSMigrationManager.
NSFetchRequest — instrumentul principal pentru interogarea obiectelor din Core Data. Interogarea conține numele entității, predicatul (filtrul), sortările, limita și deplasarea (offset). Rezultatul este returnat ca un array de NSManagedObject sau subclase tipizate. NSPredicate suportă condiții complexe cu AND, OR, IN, LIKE și subinterogări.
NSBatchDeleteRequest — o modalitate eficientă de ștergere în masă a obiectelor fără a încărca fiecare în memorie. Interogarea se execută la nivelul SQLite, ocolind managed object context, și actualizează contextul doar după finalizare. Interogări batch similare există pentru actualizare (NSBatchUpdateRequest) și inserare (NSBatchInsertRequest).
CRUD (Create, Read, Update, Delete) în Core Data se execută prin metodele contextului: insert, fetch, save și delete. Toate modificările sunt temporare până la apelul context.save() — metoda salvează modificările în stocarea persistentă SQLite. La eroare de salvare, contextul rămâne în stare modificată pentru o nouă încercare.
let context = container.viewContext
// Creare
let user = User(context: context)
user.id = 42
user.name = "Alice"
// Citire
let request = User.fetchRequest()
request.predicate = NSPredicate(format: "name CONTAINS %@", "Ali")
request.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
let results = try context.fetch(request)
// Actualizare
results.first?.name = "Alice Updated"
// Ștergere
if let first = results.first { context.delete(first) }
// Salvare
try context.save()
Salvarea contextului (context.save()) — o operație critică. Dacă salvarea nu este apelată, toate modificările rămân doar în memorie. Contextul urmărește starea hasChanges, care poate fi verificată înainte de salvare. Pentru operații de fundal, utilizați newBackgroundContext cu propria salvare, iar pentru UI — viewContext cu salvare automată la timer sau la intrarea aplicației în fundal.
Prima practică — utilizați NSPersistentCloudKitContainer pentru sincronizarea datelor între dispozitivele utilizatorului prin iCloud. Sincronizarea în cloud se activează prin adăugarea opțiunii CloudKit la descrierea stocării. Core Data gestionează automat conflictele la sincronizare și îmbină modificările de pe celelalte dispozitive.
A doua practică — evitați fetchRequest fără predicat pe tabele mari. Fiecare interogare necondiționată încarcă toate obiectele entității în memorie, ceea ce duce la un consum ridicat de RAM și încetinirea UI. Utilizați întotdeauna predicate și limite. Pentru paginare, aplicați fetchLimit și fetchOffset în NSFetchRequest.
A treia practică — configurați mergePolicy pentru rezolvarea conflictelor la accesul multi-thread. NSMergeByPropertyObjectTrumpMergePolicy actualizează proprietățile conflictuale din ultimul context salvat. NSRollbackMergePolicy anulează modificările contextului curent la conflict. Alegerea politicii depinde de logica de business a aplicației.
A patra practică — utilizați NSFetchedResultsController pentru integrarea cu tabele și colecții. Acesta se abonează automat la notificările NSManagedObjectContextDidSave, încarcă doar obiectele necesare (faulting) și notifică delegatul despre inserări, ștergeri și mutări cu căile de index corespunzătoare pentru animația UITableView.
Faulting — mecanismul de încărcare lentă a obiectelor Core Data. Managed object returnat de o interogare fetch se află în stare fault — atributele sale nu sunt încărcate complet, ci doar identificatorul. Încărcarea completă (fire fault) are loc la prima accesare a oricărui atribut. Relationship prefetching (setRelationshipKeyPathsForPrefetching) încarcă obiectele relaționate în avans, evitând interogările 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 forțează Core Data să încarce datele în loturi de câte 20 de obiecte (pentru afișare pe ecran), fără a încărca întregul tabel dintr-o dată. Flagul returnsObjectsAsFaults = false garantează că atributele tuturor utilizatorilor sunt încărcate imediat, util pentru afișarea directă. Prefetching-ul relației "posts" evită interogări separate pentru fiecare utilizator la accesarea postărilor.
Întrebări frecvente
Nu, Core Data este un framework de gestionare a grafului de obiecte. Acesta oferă API pentru lucrul cu obiecte, urmărirea modificărilor și salvarea lor. Baza de date din spatele Core Data (implicit SQLite) nu trebuie confundată cu framework-ul în sine. Core Data este un ORM, nu un SGBD.
Da, Core Data suportă trei tipuri de stocări: SQLite, Binary și In-Memory. Alegerea stocării se face prin NSPersistentStoreDescription. Stocarea In-Memory nu salvează date pe disc și este potrivită pentru testele unitare. Stocarea Binary este un format învechit pentru seturi compacte de obiecte.
Pentru migrarea ușoară, activați NSMigratePersistentStoresAutomaticallyOption și NSInferMappingModelAutomaticallyOption. Pentru modificări complexe, creați un Mapping Model (.xcmappingmodel) prin Xcode. Stocarea CloudKit (NSPersistentCloudKitContainer) suportă migrări automat la sincronizarea schemei cu serverul iCloud.
SwiftData — este un nou framework Apple (iOS 17+), construit pe deasupra Core Data cu ajutorul Swift Macros și Swift Concurrency. SwiftData este mai simplu sintactic: entitățile se descriu cu macro-ul @Model, contextul — cu @Environment(\.modelContext). Sub capotă, SwiftData folosește aceeași stivă Core Data și SQLite.
Activați argumentul de lansare -com.apple.CoreData.SQLDebug 1 — Core Data va afișa toate interogările SQL și durata lor în consola Xcode. Pentru profiling, utilizați Instruments cu șablonul Core Data, care arată numărul de interogări fault, încărcarea obiectelor și timpul de salvare a contextului.
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