Core Data для Swift: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Что такое 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". Если проект уже существует, добавьте фреймворк вручную:

  1. Выберите ваш проект в навигаторе (Project Navigator).
  2. Перейдите на вкладку "General" вашей целевой сборки (Target).
  3. Прокрутите вниз до раздела "Frameworks, Libraries, and Embedded Content".
  4. Нажмите "+" и выберите 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. Это покажет, как

Рекомендаций