Core Data — це фреймворк Apple для керування графом об'єктів у додатках iOS і macOS. Він забезпечує збереження даних, відстеження змін, скасування операцій та інтеграцію з UI через NSFetchedResultsController. Згідно з документацією Apple Developer (2025), Core Data не є базою даних — це рівень об'єктного моделювання, який за замовчуванням використовує SQLite як постійне сховище для завантаження та збереження об'єктів.
Головне
Core Data — це фреймворк керування графом об'єктів і постійності, який є частиною Cocoa Touch SDK від Apple. Він надає об'єктно-орієнтований інтерфейс для роботи з даними: розробник оперує сутностями, атрибутами та зв'язками, а Core Data перетворює ці об'єкти на записи реляційної бази даних під капотом.
Core Data був представлений у Mac OS X 10.4 Tiger (2005) для macOS і портований на iOS 3.0 (2009). За понад 20 років фреймворк еволюціонував від простого рівня абстракції над SQLite до повноцінного стека з підтримкою хмарної синхронізації через NSPersistentCloudKitContainer, багатопоточності через автоматичне керування контекстами та асинхронного завантаження через Swift Concurrency.
Згідно з опитуванням розробників iOS від Slack Community (2025), Core Data використовується в 68% комерційних iOS-додатків для локального зберігання даних. Незважаючи на критику за складність і багатошаровість, фреймворк залишається стандартом для додатків Apple завдяки тісній інтеграції з системою, нульовій вартості (вбудований у SDK) і підтримці синхронізації iCloud.
Поширена помилка — вважати Core Data базою даних. Фреймворк не виконує SQL-запити безпосередньо і не є СКБД. Core Data — це рівень керування графом об'єктів, який може використовувати SQLite, Binary або In-Memory сховище для постійності. Аналогія: Core Data — це як Hibernate або Entity Framework, але для екосистеми Apple, а SQLite під ним — як MySQL під Hibernate.
Стек Core Data складається з чотирьох взаємопов'язаних компонентів: NSManagedObjectModel (схема даних), NSPersistentStoreCoordinator (координатор сховищ), NSManagedObjectContext (робочий контекст) і NSPersistentContainer (єдиний контейнер, що об'єднує всі три з iOS 10). NSPersistentContainer автоматизує створення та налаштування стека.
Кожен компонент виконує строго визначену функцію. NSManagedObjectModel завантажує файл .xcdatamodeld з описами сутностей. NSPersistentStoreCoordinator пов'язує модель з фізичним файлом сховища (SQLite). NSManagedObjectContext надає тимчасову область для роботи з об'єктами. Контейнер об'єднує все в один виклик ініціалізації.
SQLite (NSSQLiteStoreType) — стандартне сховище, яке використовується в більшості додатків. Дані зберігаються в одному файлі .sqlite з підтримкою ACID-транзакцій. Binary (NSBinaryStoreType) — сховище в бінарному форматі для невеликих наборів даних (до кількох сотень об'єктів). In-Memory (NSInMemoryStoreType) — тимчасове сховище в оперативній пам'яті без збереження на диск, використовується для тестів і кешу.
| Тип сховища | Формат | Продуктивність | Коли використовувати |
|---|---|---|---|
| SQLite | .sqlite | Висока | Стандартний вибір для продакшну |
| Binary | .binary | Середня | Невеликі набори даних |
| In-Memory | RAM | Максимальна | Тести, кеш, тимчасові дані |
| CloudKit | iCloud | Залежить від мережі | Синхронізація між пристроями |
Вибір сховища задається єдиним рядком при ініціалізації NSPersistentStoreDescription. Розробник може переключити сховище з SQLite на In-Memory для unit-тестів або на CloudKit для синхронізації iCloud без зміни коду роботи з об'єктами — Core Data абстрагує різницю між типами сховищ за допомогою єдиного API контексту.
NSManagedObject — базовий клас для всіх об'єктів Core Data, що представляє один запис сутності. Кожен керований об'єкт має унікальний NSManagedObjectID (постійний ідентифікатор), прив'язаний до контексту та відстежує свої зміни через KVO (Key-Value Observing). Розробник створює підкласи NSManagedObject для визначення типізованих властивостей сутності.
NSManagedObjectContext — центральний компонент Core Data, що надає робочу область для всіх операцій з об'єктами. Контекст відстежує додавання, видалення та зміни об'єктів (change tracking), підтримує скасування операцій через undoManager і автоматично об'єднує зміни з інших контекстів при отриманні сповіщень про збереження.
Правило приватних черг: NSManagedObjectContext створюється з типом .privateQueueConcurrencyType або .mainQueueConcurrencyType. Головний контекст прив'язаний до головного потоку UI, а приватні контексти виконуються на фонових чергах. Кожен контекст повинен використовуватися тільки на своїй черзі — звернення до керованого об'єкта з іншого потоку викликає кеш. parentContext дозволяє організувати ієрархію контекстів для асинхронного запису.
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 автоматично створює viewContext (головна черга) і надає newBackgroundContext() для фонових операцій. Властивість automaticallyMergesChangesFromParent = true змушує viewContext автоматично підхоплювати зміни з фонових контекстів при їх збереженні, оновлюючи UI без ручного перезапиту даних.
NSPersistentStoreCoordinator керує фізичним сховищем даних: відкриває файл, створює таблиці SQLite на основі моделі та виконує міграції при зміні схеми. При ініціалізації NSPersistentStoreDescription з типом NSSQLiteStoreType Core Data створює SQLite-файл зі схемою, що відповідає моделі .xcdatamodeld.
Core Data не використовує стандартні SQL-запити через SELECT/INSERT/UPDATE. Замість цього він генерує внутрішні SQL-команди на основі моделі та запитів через NSFetchRequest. Розробник може ввімкнути логування SQL через аргумент запуску -com.apple.CoreData.SQLDebug 1 для налагодження продуктивності запитів.
Легка міграція (Lightweight Migration) — автоматичний процес оновлення схеми SQLite при додаванні нових атрибутів, зміні optional/required або перейменуванні за допомогою renamingID. Важка міграція потрібна при кардинальних змінах схеми, таких як об'єднання або розділення сутностей, і виконується через кастомний NSMigrationManager.
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)") }
}
Налаштування автоматичної міграції через NSMigratePersistentStoresAutomaticallyOption і NSInferMappingModelAutomaticallyOption дозволяє Core Data самостійно оновлювати SQLite-файл при додаванні атрибутів або сутностей у новій версії моделі. Якщо міграція неможлива, координатор сховища викидає помилку з описом причини — розробник повинен реалізувати кастомну міграцію через NSMigrationManager.
NSFetchRequest — основний інструмент для вибірки об'єктів із Core Data. Запит містить ім'я сутності, предикат (фільтр), сортування, ліміт і зміщення. Результат повертається у вигляді масиву NSManagedObject або типізованих підкласів. NSPredicate підтримує складні умови з AND, OR, IN, LIKE і підзапитами.
NSBatchDeleteRequest — ефективний спосіб масового видалення об'єктів без завантаження кожного в пам'ять. Запит виконується на рівні SQLite, оминаючи контекст керованих об'єктів, і тільки оновлює контекст після завершення. Аналогічні batch-запити існують для оновлення (NSBatchUpdateRequest) і вставки (NSBatchInsertRequest).
CRUD (Create, Read, Update, Delete) у Core Data виконується через методи контексту: insert, fetch, save і delete. Всі зміни тимчасові до виклику context.save() — метод зберігає зміни в постійне сховище SQLite. При помилці збереження контекст залишається в зміненому стані для повторної спроби.
let context = container.viewContext
// Створити
let user = User(context: context)
user.id = 42
user.name = "Alice"
// Читати
let request = User.fetchRequest()
request.predicate = NSPredicate(format: "name CONTAINS %@", "Ali")
request.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
let results = try context.fetch(request)
// Оновити
results.first?.name = "Alice Updated"
// Видалити
if let first = results.first { context.delete(first) }
// Зберегти
try context.save()
Збереження контексту (context.save()) — критична операція. Якщо збереження не викликано, всі зміни залишаються тільки в пам'яті. Контекст відстежує стан hasChanges, який можна перевірити перед збереженням. Для фонових операцій використовуйте newBackgroundContext з власним збереженням, а для UI — viewContext з автоматичним збереженням за таймером або при переході додатка у фон.
Перша практика — використовуйте NSPersistentCloudKitContainer для синхронізації даних між пристроями користувача через iCloud. Хмарна синхронізація вмикається додаванням CloudKit-опції до опису постійного сховища. Core Data автоматично керує конфліктами при синхронізації та об'єднує зміни з інших пристроїв.
Друга практика — уникайте fetchRequest без предикату на великих таблицях. Кожен безумовний fetch завантажує всі об'єкти сутності в пам'ять, що призводить до високого споживання RAM і сповільнення UI. Завжди використовуйте предикати та ліміти. Для пагінації застосовуйте fetchLimit і fetchOffset у NSFetchRequest.
Третя практика — налаштуйте mergePolicy для вирішення конфліктів при багатопоточному доступі. NSMergeByPropertyObjectTrumpMergePolicy оновлює конфліктуючі властивості з останнього збереженого контексту. NSRollbackMergePolicy скасовує зміни поточного контексту при конфлікті. Вибір політики залежить від бізнес-логіки додатка.
Четверта практика — використовуйте NSFetchedResultsController для інтеграції з таблицями та колекціями. Він автоматично підписується на сповіщення NSManagedObjectContextDidSave, завантажує тільки необхідні об'єкти (faulting) і сповіщає делегата про вставки, видалення та переміщення з відповідними index paths для анімації UITableView.
Faulting — механізм лінивого завантаження об'єктів Core Data. Керований об'єкт, повернутий fetch-запитом, знаходиться в стані fault — його атрибути завантажені не повністю, тільки ідентифікатор. Повне завантаження (fire fault) відбувається при першому зверненні до будь-якого атрибуту. Relationship prefetching (setRelationshipKeyPathsForPrefetching) завантажує пов'язані об'єкти заздалегідь, уникаючи 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 змушує Core Data завантажувати даними порціями по 20 об'єктів (для відображення на екрані), не завантажуючи одразу всю таблицю. Прапорець returnsObjectsAsFaults = false гарантує, що атрибути всіх користувачів завантажені одразу, що корисно при прямому відображенні. Prefetching зв'язку “posts” уникає окремих запитів для кожного користувача при зверненні до постів.
Часто задавані питання
Ні, Core Data — це фреймворк керування графом об'єктів. Він надає API для роботи з об'єктами, відстеження змін та їх збереження. Базу даних під капотом Core Data (за замовчуванням SQLite) не слід плутати з самим фреймворком. Core Data — це ORM, а не СКБД.
Так, Core Data підтримує три типи сховищ: SQLite, Binary і In-Memory. Вибір сховища задається через NSPersistentStoreDescription. In-Memory сховище не зберігає дані на диск і підходить для unit-тестів. Binary сховище — застарілий формат для компактних наборів об'єктів.
Для легкої міграції увімкніть NSMigratePersistentStoresAutomaticallyOption і NSInferMappingModelAutomaticallyOption. Для складних змін створіть Mapping Model (.xcmappingmodel) через Xcode. CloudKit-сховище (NSPersistentCloudKitContainer) підтримує міграції автоматично при синхронізації схеми з сервером iCloud.
SwiftData — новий фреймворк Apple (iOS 17+), побудований поверх Core Data з використанням Swift Macros і Swift Concurrency. SwiftData простіший у синтаксисі: сутності описуються макросом @Model, контекст — @Environment(\.modelContext). Під капотом SwiftData використовує той самий стек Core Data і SQLite.
Увімкніть аргумент запуску -com.apple.CoreData.SQLDebug 1 — Core Data буде виводити всі SQL-запити та їх тривалість у консоль Xcode. Для профілювання використовуйте Instruments з шаблоном Core Data, який показує кількість fault-запитів, завантаження об'єктів і час збереження контексту.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також