Core Data — ключові поняття, NSManagedObject і архітектура

Автор: IT Sectr Опубліковано: 2026-03-11 Час читання: 11 хв

Core Data — це фреймворк Apple для керування графом об'єктів у додатках iOS і macOS. Він забезпечує збереження даних, відстеження змін, скасування операцій та інтеграцію з UI через NSFetchedResultsController. Згідно з документацією Apple Developer (2025), Core Data не є базою даних — це рівень об'єктного моделювання, який за замовчуванням використовує SQLite як постійне сховище для завантаження та збереження об'єктів.

Головне

  • Core Data — це фреймворк ORM для iOS/macOS, який керує графом об'єктів і зберігає їх у сховищі.
  • NSManagedObjectModel — це схема даних, що описує сутності, атрибути та зв'язки в моделі Core Data.
  • NSManagedObjectContext — це робоча область для створення, читання, оновлення та видалення об'єктів із відстеженням змін.
  • NSPersistentContainer — це єдина точка входу, яка інкапсулює модель, контекст і сховище в iOS 10+.
  • NSFetchedResultsController інтегрує Core Data з UITableView/UICollectionView з автоматичним оновленням при змінах.

Що таке Core Data?

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 — це не база даних

Поширена помилка — вважати Core Data базою даних. Фреймворк не виконує SQL-запити безпосередньо і не є СКБД. Core Data — це рівень керування графом об'єктів, який може використовувати SQLite, Binary або In-Memory сховище для постійності. Аналогія: Core Data — це як Hibernate або Entity Framework, але для екосистеми Apple, а SQLite під ним — як MySQL під Hibernate.

Архітектура Core Data: стеки та компоненти

Стек Core Data складається з чотирьох взаємопов'язаних компонентів: NSManagedObjectModel (схема даних), NSPersistentStoreCoordinator (координатор сховищ), NSManagedObjectContext (робочий контекст) і NSPersistentContainer (єдиний контейнер, що об'єднує всі три з iOS 10). NSPersistentContainer автоматизує створення та налаштування стека.

Кожен компонент виконує строго визначену функцію. NSManagedObjectModel завантажує файл .xcdatamodeld з описами сутностей. NSPersistentStoreCoordinator пов'язує модель з фізичним файлом сховища (SQLite). NSManagedObjectContext надає тимчасову область для роботи з об'єктами. Контейнер об'єднує все в один виклик ініціалізації.

Типи сховищ Core Data

SQLite (NSSQLiteStoreType) — стандартне сховище, яке використовується в більшості додатків. Дані зберігаються в одному файлі .sqlite з підтримкою ACID-транзакцій. Binary (NSBinaryStoreType) — сховище в бінарному форматі для невеликих наборів даних (до кількох сотень об'єктів). In-Memory (NSInMemoryStoreType) — тимчасове сховище в оперативній пам'яті без збереження на диск, використовується для тестів і кешу.

Тип сховищаФорматПродуктивністьКоли використовувати
SQLite.sqliteВисокаСтандартний вибір для продакшну
Binary.binaryСередняНевеликі набори даних
In-MemoryRAMМаксимальнаТести, кеш, тимчасові дані
CloudKitiCloudЗалежить від мережіСинхронізація між пристроями

Вибір сховища задається єдиним рядком при ініціалізації NSPersistentStoreDescription. Розробник може переключити сховище з SQLite на In-Memory для unit-тестів або на CloudKit для синхронізації iCloud без зміни коду роботи з об'єктами — Core Data абстрагує різницю між типами сховищ за допомогою єдиного API контексту.

NSManagedObject і NSManagedObjectContext

NSManagedObject — базовий клас для всіх об'єктів Core Data, що представляє один запис сутності. Кожен керований об'єкт має унікальний NSManagedObjectID (постійний ідентифікатор), прив'язаний до контексту та відстежує свої зміни через KVO (Key-Value Observing). Розробник створює підкласи NSManagedObject для визначення типізованих властивостей сутності.

NSManagedObjectContext — центральний компонент Core Data, що надає робочу область для всіх операцій з об'єктами. Контекст відстежує додавання, видалення та зміни об'єктів (change tracking), підтримує скасування операцій через undoManager і автоматично об'єднує зміни з інших контекстів при отриманні сповіщень про збереження.

Потокобезпечність контекстів

Правило приватних черг: NSManagedObjectContext створюється з типом .privateQueueConcurrencyType або .mainQueueConcurrencyType. Головний контекст прив'язаний до головного потоку UI, а приватні контексти виконуються на фонових чергах. Кожен контекст повинен використовуватися тільки на своїй черзі — звернення до керованого об'єкта з іншого потоку викликає кеш. parentContext дозволяє організувати ієрархію контекстів для асинхронного запису.

swift
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 без ручного перезапиту даних.

Постійне сховище та SQLite

NSPersistentStoreCoordinator керує фізичним сховищем даних: відкриває файл, створює таблиці SQLite на основі моделі та виконує міграції при зміні схеми. При ініціалізації NSPersistentStoreDescription з типом NSSQLiteStoreType Core Data створює SQLite-файл зі схемою, що відповідає моделі .xcdatamodeld.

Core Data не використовує стандартні SQL-запити через SELECT/INSERT/UPDATE. Замість цього він генерує внутрішні SQL-команди на основі моделі та запитів через NSFetchRequest. Розробник може ввімкнути логування SQL через аргумент запуску -com.apple.CoreData.SQLDebug 1 для налагодження продуктивності запитів.

Міграції Core Data

Легка міграція (Lightweight Migration) — автоматичний процес оновлення схеми SQLite при додаванні нових атрибутів, зміні optional/required або перейменуванні за допомогою renamingID. Важка міграція потрібна при кардинальних змінах схеми, таких як об'єднання або розділення сутностей, і виконується через кастомний NSMigrationManager.

swift
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.

Core Data на практиці: код і приклади

NSFetchRequest — основний інструмент для вибірки об'єктів із Core Data. Запит містить ім'я сутності, предикат (фільтр), сортування, ліміт і зміщення. Результат повертається у вигляді масиву NSManagedObject або типізованих підкласів. NSPredicate підтримує складні умови з AND, OR, IN, LIKE і підзапитами.

NSBatchDeleteRequest — ефективний спосіб масового видалення об'єктів без завантаження кожного в пам'ять. Запит виконується на рівні SQLite, оминаючи контекст керованих об'єктів, і тільки оновлює контекст після завершення. Аналогічні batch-запити існують для оновлення (NSBatchUpdateRequest) і вставки (NSBatchInsertRequest).

Приклад CRUD-операцій

CRUD (Create, Read, Update, Delete) у Core Data виконується через методи контексту: insert, fetch, save і delete. Всі зміни тимчасові до виклику context.save() — метод зберігає зміни в постійне сховище SQLite. При помилці збереження контекст залишається в зміненому стані для повторної спроби.

swift
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 з автоматичним збереженням за таймером або при переході додатка у фон.

Найкращі практики Core Data

Перша практика — використовуйте NSPersistentCloudKitContainer для синхронізації даних між пристроями користувача через iCloud. Хмарна синхронізація вмикається додаванням CloudKit-опції до опису постійного сховища. Core Data автоматично керує конфліктами при синхронізації та об'єднує зміни з інших пристроїв.

Друга практика — уникайте fetchRequest без предикату на великих таблицях. Кожен безумовний fetch завантажує всі об'єкти сутності в пам'ять, що призводить до високого споживання RAM і сповільнення UI. Завжди використовуйте предикати та ліміти. Для пагінації застосовуйте fetchLimit і fetchOffset у NSFetchRequest.

Третя практика — налаштуйте mergePolicy для вирішення конфліктів при багатопоточному доступі. NSMergeByPropertyObjectTrumpMergePolicy оновлює конфліктуючі властивості з останнього збереженого контексту. NSRollbackMergePolicy скасовує зміни поточного контексту при конфлікті. Вибір політики залежить від бізнес-логіки додатка.

Четверта практика — використовуйте NSFetchedResultsController для інтеграції з таблицями та колекціями. Він автоматично підписується на сповіщення NSManagedObjectContextDidSave, завантажує тільки необхідні об'єкти (faulting) і сповіщає делегата про вставки, видалення та переміщення з відповідними index paths для анімації UITableView.

Продуктивність: prefetching і faulting

Faulting — механізм лінивого завантаження об'єктів Core Data. Керований об'єкт, повернутий fetch-запитом, знаходиться в стані fault — його атрибути завантажені не повністю, тільки ідентифікатор. Повне завантаження (fire fault) відбувається при першому зверненні до будь-якого атрибуту. Relationship prefetching (setRelationshipKeyPathsForPrefetching) завантажує пов'язані об'єкти заздалегідь, уникаючи N+1 запитів.

swift
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 — це база даних?

Ні, Core Data — це фреймворк керування графом об'єктів. Він надає API для роботи з об'єктами, відстеження змін та їх збереження. Базу даних під капотом Core Data (за замовчуванням SQLite) не слід плутати з самим фреймворком. Core Data — це ORM, а не СКБД.

Чи можна використовувати Core Data без SQLite?

Так, Core Data підтримує три типи сховищ: SQLite, Binary і In-Memory. Вибір сховища задається через NSPersistentStoreDescription. In-Memory сховище не зберігає дані на диск і підходить для unit-тестів. Binary сховище — застарілий формат для компактних наборів об'єктів.

Як перенести Core Data на нову версію моделі?

Для легкої міграції увімкніть NSMigratePersistentStoresAutomaticallyOption і NSInferMappingModelAutomaticallyOption. Для складних змін створіть Mapping Model (.xcmappingmodel) через Xcode. CloudKit-сховище (NSPersistentCloudKitContainer) підтримує міграції автоматично при синхронізації схеми з сервером iCloud.

Чим Core Data відрізняється від SwiftData?

SwiftData — новий фреймворк Apple (iOS 17+), побудований поверх Core Data з використанням Swift Macros і Swift Concurrency. SwiftData простіший у синтаксисі: сутності описуються макросом @Model, контекст — @Environment(\.modelContext). Під капотом SwiftData використовує той самий стек Core Data і SQLite.

Як налагодити повільні запити Core Data?

Увімкніть аргумент запуску -com.apple.CoreData.SQLDebug 1 — Core Data буде виводити всі SQL-запити та їх тривалість у консоль Xcode. Для профілювання використовуйте Instruments з шаблоном Core Data, який показує кількість fault-запитів, завантаження об'єктів і час збереження контексту.

Підсумки

  • Core Data — фреймворк керування графом об'єктів і постійності для iOS і macOS, який використовує SQLite як стандартне сховище.
  • Стек Core Data включає NSManagedObjectModel, NSPersistentStoreCoordinator, NSManagedObjectContext і NSPersistentContainer для єдиної конфігурації.
  • NSManagedObjectContext — робоча область з відстеженням змін, підтримкою скасування та автоматичним об'єднанням із фонових контекстів.
  • NSFetchRequest з NSPredicate та prefetching зв'язків — основний інструмент вибірки з оптимізацією через batch size і faulting.
  • Lightweight Migration автоматично оновлює схему SQLite при додаванні атрибутів і сутностей у новій версії моделі.
  • NSPersistentCloudKitContainer додає синхронізацію iCloud між пристроями користувача з автоматичним вирішенням конфліктів.
  • Рекомендація — використовуйте Core Data для iOS-додатків з ієрархічними об'єктними моделями, а для простого локального зберігання розгляньте GRDB або SwiftData.

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також