Core Data е рамка за управление на данни от Apple, която предоставя обектно-релационно съпоставяне за iOS, macOS, tvOS и watchOS. Тя автоматизира запазването, извличането и филтрирането на обекти в приложението, работейки върху SQLite, XML или бинарно хранилище. Според Apple Core Data Documentation, рамката използва концепциите Managed Object Context и NSPersistentContainer за управление на стека за персистентност.
Основни точки
Core Data — е рамка за управление на обектен граф и персистентност, която е част от Cocoa Touch. Противно на разпространеното погрешно схващане, Core Data не е база данни, а слой за управление на обекти, който може да използва SQLite като едно от хранилищата. Основната задача на Core Data е да проследява промените на обектите, да управлява техния жизнен цикъл и да синхронизира състоянието с диска.
Рамката предоставя обектен граф, където всеки Managed Object се проследява от контекста за промени. При запазване на контекста, всички променени, добавени и изтрити обекти се потвърждават в постоянното хранилище с една транзакция. Това освобождава разработчика от писане на SQL заявки и ръчно управление на транзакции.
Според статистиката на Swift Developer Survey (2025), Core Data се използва в 52% от iOS приложенията, работещи с локални данни. Въпреки появата на модерни алтернативи (SwiftData, Realm), Core Data остава основната рамка в съществуващите проекти на Apple благодарение на зрелостта си и дълбоката интеграция със системата.
Използвайте Core Data за проекти с модел на данни със средна сложност, където са необходими връзки между обекти, отмяна на промени и автоматично кеширане чрез механизма faulting.
Архитектурата на Core Data е изградена около концепцията на Managed Object Context — работно пространство, което проследява всички промени на обектите. Контекстът поддържа отмяна (undo/redo) чрез вградения NSUndoManager, което позволява реализиране на чернови и отмяна на действия без ръчно запазване на моментни снимки на състоянието. При извикване на save() контекстът потвърждава всички промени с една транзакция в постоянното хранилище, гарантирайки атомарност и консистентност на данните.
Моделът на данни на Core Data се дефинира във файла .xcdatamodeld — визуалния редактор на Xcode, където се описват всички Entity, техните атрибути и връзки. При компилация моделът се сериализира в .momd и се зарежда чрез NSManagedObjectModel.
Entity — е описание на тип данни, аналогично на таблица в SQL. Всяка Entity съдържа набор от Attributes — именувани полета с тип данни (String, Integer, Date, Boolean, Data). За разлика от Room, Core Data изисква изричен избор на тип за всеки атрибут чрез редактора на модела.
Relationship — връзка между Entity, аналогична на външен ключ в SQL. Core Data поддържа всички типове връзки: едно-към-едно, едно-към-много и много-към-много. За всяка връзка се конфигурира Delete Rule (Cascade, Nullify, Deny) — поведението при изтриване на свързания обект.
| Delete Rule | Поведение при изтриване | Пример за приложение |
|---|---|---|
| Cascade | Изтрива всички свързани обекти | Изтриване на поръчка заедно с позициите |
| Nullify | Нулира обратната връзка | Изтриване на автор без изтриване на книги |
| Deny | Блокира изтриването, ако има свързани обекти | Защита от изтриване на категория с продукти |
Изборът на Delete Rule е критичен за целостта на данните: Cascade без проверка може да изтрие една трета от базата, а Deny може да блокира операцията с неразбираема грешка. В продукционен код се препоръчва Nullify с ръчна обработка на осиротели записи.
В редактора на модела на Xcode разработчикът може да задава не само Entity и атрибути, но и constraints (ограничения за уникалност), индекси за ускоряване на заявки и default values за атрибути. Всички промени в модела се компилират във файла .momd, който се зарежда при инициализация на NSPersistentContainer. Версионирането на модела (Model Versioning) позволява поддържане на няколко версии на схемата и извършване на миграция между тях.
NSPersistentContainer — единен обект, управляващ стека на Core Data от iOS 10 и macOS 10.12. Той капсулира NSManagedObjectModel, NSPersistentStoreCoordinator и NSManagedObjectContext, автоматизирайки зареждането на модела и конфигурирането на хранилището. За по-стари версии стекът се изграждаше ръчно, но сега това не се препоръчва.
let container = NSPersistentContainer(name: "DataModel")
container.loadPersistentStores { _, error in
if let error { fatalError("Core Data load failed: \(error)") }
}
let context = container.viewContext
viewContext — основният контекст, свързан с главната нишка. Всички четения и актуализации на UI се извършват чрез него. Записването на данни за производителност се препоръчва да се извършва в дъщерен контекст с частна опашка и последваща синхронизация.
Координаторът NSPersistentStoreCoordinator свързва модела с физическото хранилище на диска. Core Data поддържа няколко типа хранилища: SQLite (препоръчвано), Binary и In-Memory. SQLite хранилището поддържа миграции, инкрементално архивиране и устойчивост на грешки по време на процеса на запис.
NSFetchRequest — обект, описващ заявка към хранилището на Core Data. Той съдържа името на Entity, предикат за филтриране, сортиране и настройки за извличане. Заявката се изпълнява чрез context.fetch(), който връща масив от 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 поддържа сложни условия: LIKE, IN, BETWEEN, CONTAINS[c] (нечувствителен към главни и малки букви), SUBQUERY за вложени заявки по свързани Entity. Core Data също поддържа NSFetchedResultsController — клас за реактивно зареждане на данни в UITableView, който автоматично проследява промените и актуализира таблицата с анимирани секции.
Работата с Core Data в многонишково приложение изисква стриктно спазване на правилата: NSManagedObject не може да се предава директно между нишки. Всяка нишка (или опашка) трябва да използва свой собствен контекст. Основният подход е създаване на дъщерен NSManagedObjectContext с частна опашка (NSPrivateQueueConcurrencyType) за запис и viewContext за четене.
Дъщерният контекст се запазва в родителския, а след това родителският — в хранилището на диска. Това гарантира, че промените не блокират главната нишка и че UI винаги вижда консистентно състояние чрез mergeChanges или автоматично актуализиране на viewContext при запазване.
Core Data използва faulting — механизъм за отложено зареждане на свързани обекти. При извличане на User без запитване за неговите addresses, свързаните Address не се зареждат, докато не бъдат достъпени чрез точкова нотация. Faulting спестява памет и ускорява зареждането, но може да причини неочаквани достъпи до диска на главната нишка, ако достъпът не се контролира във фонов контекст.
За ефективна многонишковост използвайте NSBatchInsertRequest и NSBatchDeleteRequest за масово вмъкване и изтриване без зареждане на обекти в паметта — това е критично за синхронизиране на данни със сървъра.
Batch операциите се изпълняват директно на ниво NSPersistentStoreCoordinator, заобикаляйки контекста и обектния граф. Това позволява вмъкване на 10 000 записа за няколко милисекунди без създаване на 10 000 инстанции на NSManagedObject в паметта. След изпълнение на batch заявката, контекстът трябва да се актуализира чрез mergeChangesFromContextDidSaveNotification, за да може UI да отрази новите данни. Apple препоръчва batch операции за първоначално зареждане на данни и нощна синхронизация със сървъра.
За проследяване на промените в Core Data се използва NSPersistentHistoryTracking — механизъм, който записва всяка транзакция (вмъкване, актуализиране, изтриване) в отделна история. Активирането на history tracking позволява синхронизиране на данни между различни процеси и приложения, работещи с един и същ SQLite файл, например между основното приложение и Notification Service Extension. Активирането става чрез NSPersistentStoreDescription с флага persistentHistoryTrackingKey, а четенето — чрез NSPersistentHistoryChangeRequest с филтър по дата и тип транзакция.
За отстраняване на грешки и профилиране на производителността на Core Data се използва инструментът Core Data Profiler от комплекта Instruments в Xcode на macOS. Той показва всички операции по извличане, вмъкване, изтриване и запазване с продължителността на всяка операция и броя на заредените обекти в таблици и графики на времевата линия. Разработчикът може да идентифицира проблемни области: многократни извличания на една и съща заявка (липса на кеширане), изтичане на fault обекти при превъртане на таблица или блокиране на главната нишка поради синхронно зареждане на свързани обекти. Препоръчва се профилиране на реално устройство, а не на симулатор, тъй като производителността на симулатора не отразява реалното поведение на приложението на iPhone или iPad.
Често задавани въпроси
Core Data — не е база данни, а слой за управление на обекти, който може да използва SQLite като хранилище. За разлика от директния SQLite, Core Data проследява промените на обектите, управлява отмяната и предоставя обектен граф с faulting и кеширане. SQLite дава повече контрол върху заявките, но изисква писане на SQL и ръчно управление на транзакции.
Core Data поддържа лека миграция (Lightweight Migration) за неразрушаващи промени: добавяне на атрибут, преименуване, задаване на стойност по подразбиране. За сложни промени се създава Mapping Model. Леката миграция се включва чрез флага shouldMigrateAutomatically в NSPersistentStoreDescription.
Да, Core Data се интегрира със SwiftUI чрез обвивката @FetchRequest за заявки и @ObservedObject за абонамент за промени. SwiftUI автоматично актуализира View при промяна на ManagedObject, което прави Core Data и SwiftUI съвместим стек за управление на състоянието.
Fault — е лек заместител в графа на Core Data, който не съдържа данни на свързания обект. При задаване на fault (чрез refreshObject:) данните се освобождават от паметта. При достъп до свойство, fault се попълва автоматично с данни от хранилището — това е механизъм за отложено зареждане, който оптимизира използването на паметта.
За тестване използвайте In-Memory тип хранилище: NSPersistentStoreDescription с NSInMemoryStoreType. Контейнерът се създава с модела от тестовия пакет. След всеки тест изтрийте всички обекти или пресъздайте контейнера — това гарантира изолиране на тестовите случаи един от друг.
Резюме
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също