Тем с Core Data уже написана большое количество, но большинство этих статей на английском языке, а так же с использованием большого количества «умных» слов которые могут запутать новичков.

В данной статье я постараюсь рассказать о данном фреймворке от Apple понятным языком, чтобы даже «самые маленькие» программисты смогли вынести для себя информацию, и получить тот минимальный обьем знаний который поможет им в своих проектах либо.

Небольшой оффтоп


Core Data очень мощный инструмент, который позволяет вам сохранять данные в вашем приложении и использовать их в дальнейшем. В этой статье я НЕ буду рассказывать о работе с multiple context с последующей синхронизацией, как решать проблемы миграции и различные advance фишки.

Целевая аудитория этой статьи люди которые вообще не имели никакого опыта работы с Core Data.

Ну что ж… Начнем!


Для начала, вам нужно создать сам .xcdatamodeld файл, после того как вы откроете его, то внизу экрана вы увидите кнопку «Add entity». Нажав на нее у вас создастся ваша модель объекта:



А теперь по-подробнее:

  1. Ваш Entity. Вы можете думать об Entity как о вашей структуре данных, которая имеет наследование от определенного класса — NSManagedObject, а так же будет иметь определенные поля для записи данных, об этом далее.
  2. Поле Attributes. Это атрибуты вашего Entity о котором говорилось выше. По нажатию на + вы можете добавить необходимый для вас атрибут. Атрибуты бывают следующих видов:
    • Integer 16/32/64 — используйте этот тип если хотите сохранить целочисленное значение. Разница между этими значениями лишь в том, насколько большое число вы можете сохранить. Так же чтобы сохранить число типа Int, вы должны привести его к одному из этих значнией.
      Пример: Integer16(15)
    • Decimal/Double/Float — используйте этот тип если хотите сохранить число с плавающей точкой. Разница между этими значениями лишь в том, сколько цифр после точки будет сохранено.
    • String — используйте этот тип если хотите сохранить строковое значение.
    • Boolean — используйте этот тип если хотите сохранить булевский оператор.
    • Date — используйте этот тип если хотите сохранить тип Date.
      NOTE: Core Data проводит операцию конвертации и просто сохраняет число в секундах с 00:00:00 UTC 1 Января 1970 до вашей даты.
    • Binary Data — используйте этот тип если хотите сохранить Data
      NOTE: Всегда ставьте чекмарк на поле Allow External Storage. Core Data проверяет обьем данных, и если он превышает 100 килобайт, то данные будут сохранены отдельно от Core Data а данное поле будет хранить ссылку на объект. Это улучшит производительность приложения и избавит от ненужных проблем с памятью.
    • UUID — используйте этот тип если хотите сохранить уникальный идентификатор типа UUID.
    • URI — используйте этот тип если хотите сохранить ссылку URL
    • Transformable — позволяет сохранить кастомный тип данных, однако эти данные должны поддерживать протокол NSCoding.

  3. Поле Relationship. В этом поле вы можете назначать взаимосвязи с другими вашими Entity. Relationships могут быть:

    1. One-to-One
    2. One-to-Many
    3. Many-to-Many

    Пример использования Relationships.

    У нас есть 3 Entities, Andrey, Home, Car.

    • У Андрея только один дом — One-to-One Relationship.
    • У Андрея может быть 1, а может быть 2 и более автомобиля — One-to-Many Relationship.
    • Примером Many-to-Many Relationship может быть страны и города. В странах может быть схожее количество городов с одинаковым название и в свою очередь город с одним названием может появляться в разных странах.
  4. В этом поле вы можете изменить имя для вашего Entity
  5. Поле Codegen. Если говорить вкратце то это поле указывать кем будет регулироваться создание NSManagedObject классов. Для простоты работы выбирайте Manual/None, далее Core Data сможет сама создать необходимые классы для ваших Entity. Об этом ниже.

Чтобы создать класс наших Entity используйте:

Editor > Create NSManagedObject Subclass



Если вы хотите задать дефолтные значения для ваших атрибутов используйте метод:

public override func awakeFromInsert() {
        super.awakeFromInsert()
        date = Date()
}

Работа с NSManagedObjectContext и PersistentStoreCoordinator


Иерархия Core Data Stack:



Если простыми словами, то все ваши Entity изображены на данной диаграмме сверху как Managed Object. Все наши Managed Objects хранятся в NSManagedObjectContext. Context Ссылается на NSPersistentStoreCoordinator который хранит после обращения к SQL ваши сохраненные данные в виде Row Cache, однако сейчас не об этом.

Чтобы создать экземпляр вашего ManagedObject(Entity), вы должны обратиться к своему NSPersistentContainer который является оберткой для вашего NSPersistentStoreCoordinator.

var persistentContainer: NSPersistentContainer = {
      let container = NSPersistentContainer(name: "SavingLearn")
      container.loadPersistentStores(completionHandler: { (storeDescription, error) in
          if let error = error as NSError? {
              fatalError("Unresolved error \(error), \(error.userInfo)")
          }
      })
      return container
  }()

Далее мы должны обратиться к NSManagedObjectContext через наш PersistentContainer:

var context: NSManagedObjectContext = {
    return persistentContainer.viewContext
  }()

Теперь мы можем создать экземпляр нашего ManageObject из нашего контекста и присвоить ему значение:

var person = Person(context: context)
person.age = 32

Сохранение объекта


Для сохранения используем простую функцию:

func saveContext () {
      if context.hasChanges {
          do {
              try context.save()
          } catch {
            context.rollback()
              let nserror = error as NSError
              fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
          }
      }
  }

В методе выше мы проверяем наш контекст на изменения и если они присутствуют мы делаем сохранение. В случае ошибки выполняется метод:

context.rollback()

rollback()
Метод делает возврат нашего контекста в первоначальное состояние и отменяет все изменения которые проводились над ним

Удаление объекта

context.delete(object)

Позволяет нам легко удалить объект из Core Data.
NOTE: Чтобы изменения вступили в силу требуется выполнить сохранение контекста, иначе все изменения не сохраняться.
context.save()

Получение всех объектов


Для того чтобы получить массив наших объектов из Core Data мы должный выполнить NSFetchRequest. Я не буду глубоко углубляться во всю мощь FetchRequest так как эта статься рассчитана на новичков.

let fetchRequest: NSFetchRequest<Person> = Person.fetchRequest()
let objects = try context.fetch(fetchRequest)

Под капотом NSFetchRequest делает огромную работу:

  1. NSFetchRequest отправляется в Persistent Store Coordinator
  2. Persistent Store Coordinator отправляет запрос в Persistent Store
  3. Persistent Store отправляет отправляет запрос в SQL
  4. SQL делает запрос и выдает все подходящие строки. Каждая строка имеет ID и Row Value. Это Row Value передается в Persistent Store и храниться там в виде Row Cache со своим ID.
  5. Persistent Store инициализирует Managed Objects для определенных ID и возвращает их в Persistent Store Coordinator. Полученные данные являются fault (пустыми) до того момента пока мы не обратимся к конкретному объекту. Если в Managed Object Context уже был объект с нужным ID, Core Data не будет отправлять запрос ниже к SQL.
  6. Persistent Store Coordinator возвращает в context массив Managed Object
  7. Перед возвращением объекта Core Data проверяет объекты на изменения. Чтобы убрать это поведение можете установить флаг
    includePendingChanges = false
  8. Возвращается массив NSManagedObject

NOTE: Пока выполняется NSFetchRequest Managed Object Context и Persistent Store Coordinator выполняется в синхронной очереди и все процессы блокируются пока другой процесс отрабатывается

Заключение


В данной статье я описал минимальную информацию необходимую для работы с Core Data по-моему мнению.

Теперь вы можете создавать свои собственные модели данных, сохранять, удалять и получать их.

Если вас интересует более «advance» топик о работе с Core Data и интересные tips, то пишите в комментарии и я придумаю, что можно с этим сделать. Happy Coding!