Что такое Core Data и зачем она нужна?
Core Data — это не библиотека в традиционном понимании (как, например, Alamofire или SnapKit), а мощный фреймворк от Apple для управления моделью данных и обеспечения персистентности (сохранения) данных в приложениях под iOS, macOS, tvOS и watchOS. Он встроен в SDK и не требует отдельной установки через менеджеры пакетов, такие как CocoaPods или Swift Package Manager.
Зачем нужен Core Data? В современной разработке мобильных приложений почти всегда требуется хранить данные локально: будь то список задач, история сообщений, настройки пользователя или кэш новостей. Core Data предоставляет для этого полноценный стек, который включает:
- Модель данных (NSManagedObjectModel) — описание сущностей, их атрибутов и связей.
- Контекст (NSManagedObjectContext) — "черновик", где вы работаете с объектами до их сохранения.
- Persistent Store Coordinator — мост между контекстом и физическим хранилищем (SQLite, XML, бинарный файл и т.д.).
- Persistent Container — упрощенная обертка (появилась в iOS 10), которая объединяет все компоненты.
В отличие от простого использования SQLite или UserDefaults, Core Data автоматически управляет жизненным циклом объектов, поддерживает откат изменений, ленивую загрузку, кэширование, валидацию и даже интеграцию с iCloud. Это делает его незаменимым инструментом для любого серьезного приложения, работающего с данными.
Установка Core Data
Core Data является частью системных фреймворков Apple. Вам не нужно выполнять pip install или npm install. Для его использования достаточно импортировать фреймворк в ваш проект.
1. Добавление фреймворка в проект
При создании нового проекта в Xcode вы можете сразу поставить галочку "Use Core Data". Если проект уже существует, добавьте фреймворк вручную:
- Выберите ваш проект в навигаторе (Project Navigator).
- Перейдите на вкладку "General" вашей целевой сборки (Target).
- Прокрутите вниз до раздела "Frameworks, Libraries, and Embedded Content".
- Нажмите "+" и выберите
CoreData.framework.
2. Создание файла модели данных
Вам также понадобится файл с расширением .xcdatamodeld. Обычно он создается автоматически при включении Core Data. Если его нет, создайте новый файл: File → New → File → Core Data → Data Model.
3. Импорт в коде
В файлах Swift, где вы будете работать с Core Data, добавьте:
import CoreData
На этом установка завершена. Core Data готов к использованию.
Быстрый старт: пример кода
Рассмотрим простейший пример: создание сущности "User" с атрибутами "name" и "age", сохранение и чтение данных.
Шаг 1: Создаем модель данных
Откройте файл .xcdatamodeld. Добавьте сущность (Entity) с именем "User". Добавьте атрибуты: name (тип String) и age (тип Int16). Создайте класс для этой сущности: Editor → Create NSManagedObject Subclass. Xcode сгенерирует файлы User+CoreDataProperties.swift и User+CoreDataClass.swift.
Шаг 2: Настройка Persistent Container
В AppDelegate (или в отдельном менеджере) создаем контейнер:
import CoreData
class PersistenceController {
static let shared = PersistenceController()
let container: NSPersistentContainer
init() {
container = NSPersistentContainer(name: "YourModelName") // Имя вашего .xcdatamodeld файла
container.loadPersistentStores { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
}
}
var context: NSManagedObjectContext {
return container.viewContext
}
}
Шаг 3: Сохранение данных
let context = PersistenceController.shared.context
// Создаем нового пользователя
let newUser = User(context: context)
newUser.name = "Иван Петров"
newUser.age = 30
// Сохраняем контекст
do {
try context.save()
print("Пользователь сохранен!")
} catch {
print("Ошибка сохранения: \(error)")
}
Шаг 4: Чтение данных
let fetchRequest: NSFetchRequest<User> = User.fetchRequest()
do {
let users = try context.fetch(fetchRequest)
for user in users {
print("Имя: \(user.name ?? "Нет имени"), Возраст: \(user.age)")
}
} catch {
print("Ошибка чтения: \(error)")
}
Этот минимальный пример демонстрирует базовый цикл работы с Core Data: создание контекста, добавление объекта, сохранение и запрос.
Основные методы и функции Core Data
Ниже приведен подробный разбор ключевых методов, которые вы будете использовать чаще всего.
1. NSPersistentContainer(name:)
Что делает: Инициализирует контейнер, который управляет всем стеком Core Data: моделью, координатором и контекстом. Это основной класс для работы с Core Data, начиная с iOS 10.
Параметры:
name: String— имя файла модели данных (без расширения .xcdatamodeld).
Рабочий пример:
let container = NSPersistentContainer(name: "MyAppDataModel")
container.loadPersistentStores { (description, error) in
if let error = error {
print("Ошибка загрузки стора: \(error)")
}
}
2. container.viewContext
Что делает: Возвращает основной контекст для работы с данными в главном потоке (Main Queue). Используется для UI-операций.
Параметры: Нет.
Рабочий пример:
let context = PersistenceController.shared.container.viewContext
// Теперь context можно использовать для создания и запросов объектов
3. context.save()
Что делает: Сохраняет все изменения, сделанные в контексте, в постоянное хранилище (обычно SQLite). Если не вызвать save, данные будут потеряны при завершении приложения.
Параметры: Нет (метод выбрасывает ошибку).
Рабочий пример:
do {
try context.save()
print("Изменения сохранены")
} catch {
print("Не удалось сохранить: \(error)")
}
4. NSFetchRequest<T>.init(entityName:)
Что делает: Создает запрос для извлечения объектов определенного типа из хранилища. Это основной способ чтения данных.
Параметры:
entityName: String— имя сущности (например, "User").
Рабочий пример:
let fetchRequest = NSFetchRequest<User>(entityName: "User")
// Или используя сгенерированный метод:
// let fetchRequest: NSFetchRequest<User> = User.fetchRequest()
5. context.fetch(request)
Что делает: Выполняет запрос и возвращает массив объектов, соответствующих критериям. Может выбрасывать ошибку.
Параметры:
request: NSFetchRequest<T>— запрос, который нужно выполнить.
Рабочий пример:
let request: NSFetchRequest<User> = User.fetchRequest()
do {
let users = try context.fetch(request)
for user in users {
print(user.name ?? "")
}
} catch {
print("Ошибка запроса: \(error)")
}
6. NSPredicate(format:)
Что делает: Создает предикат для фильтрации результатов запроса. Позволяет искать объекты по условиям (например, "возраст больше 18").
Параметры:
format: String— строка с условием (например, "age > %@").argumentArray: [Any]?— массив аргументов для подстановки в формат.
Рабочий пример:
let predicate = NSPredicate(format: "age > %@", NSNumber(value: 18))
let request: NSFetchRequest<User> = User.fetchRequest()
request.predicate = predicate
let adultUsers = try context.fetch(request)
7. NSSortDescriptor(key:ascending:)
Что делает: Определяет порядок сортировки результатов запроса по указанному ключу (атрибуту).
Параметры:
key: String— имя атрибута для сортировки.ascending: Bool— true для сортировки по возрастанию, false — по убыванию.
Рабочий пример:
let sortDescriptor = NSSortDescriptor(key: "age", ascending: false)
let request: NSFetchRequest<User> = User.fetchRequest()
request.sortDescriptors = [sortDescriptor]
// Теперь пользователи будут отсортированы по возрасту от старшего к младшему
8. context.delete(object)
Что делает: Помечает объект для удаления. Фактическое удаление произойдет только после вызова save().
Параметры:
object: NSManagedObject— объект, который нужно удалить.
Рабочий пример:
let request: NSFetchRequest<User> = User.fetchRequest()
request.predicate = NSPredicate(format: "name == %@", "Иван Петров")
if let userToDelete = try context.fetch(request).first {
context.delete(userToDelete)
try context.save()
print("Пользователь удален")
}
9. container.newBackgroundContext()
Что делает: Создает новый контекст для работы в фоновом потоке. Это критически важно для тяжелых операций (импорт больших данных), чтобы не блокировать UI.
Параметры: Нет.
Рабочий пример:
let backgroundContext = PersistenceController.shared.container.newBackgroundContext()
backgroundContext.perform {
// Тяжелая работа в фоне
for i in 0..<1000 {
let user = User(context: backgroundContext)
user.name = "User \(i)"
}
try? backgroundContext.save()
// Возвращаемся на главный поток для обновления UI
DispatchQueue.main.async {
// Обновить таблицу и т.д.
}
}
10. context.rollback()
Что делает: Отменяет все незафиксированные изменения в контексте. Полезно, если пользователь нажал "Отмена" в форме редактирования.
Параметры: Нет.
Рабочий пример:
// Пользователь начал редактирование, но решил отменить
if userCancelled {
context.rollback()
print("Все изменения отменены")
}
Реальный практический пример: Приложение "Список задач" (To-Do List)
Давайте создадим полноценное приложение для управления задачами, используя Core Data. Это покажет, как