Сохранение рисунков пользователя в Core Data

Трансформируемые атрибуты полезны для хранения нестандартных типов объектов в Core Data.

Например, вы можете сохранить экземпляр UIImage в Core Data, установив для его типа атрибута значение Transformable.

В этой статье мы пойдем еще дальше, чтобы увидеть, как мы можем хранить массив пользовательских типов данных в Core Data с помощью Transformable и NSSecureCoding.

Представьте, что мы хотим хранить рисунки пользователя в Core Data для вымышленного приложения для рисования. Мы создали 2 класса для моделирования данных чертежа:

И в нашем собственном подклассе холста UIView мы рисуем наши пути следующим образом:

Теперь пришло время сохранить данные чертежа в Core Data.

Давайте откроем наш редактор модели CoreData (исходный файл с расширением .xcdatamodeld) и добавим атрибут с именем drawings для нашего объекта Canvas, а затем установим его тип атрибута на Transformable.

Но теперь мы получаем предупреждение, в котором говорится:

Canvas.drawing использует нулевой или небезопасный преобразователь значений. Переключитесь на NSSecureUnarchiveFromDataTransformerName или на собственный NSValueTransformer подкласс NSSecureUnarchiveFromDataTransformer

Причина, по которой мы получаем это предупреждение, заключается в том, что, начиная с iOS 13, Apple хочет, чтобы мы использовали NSSecureCoding (а не NSCoding) для наших пользовательских типов данных CoreData для повышения безопасности.

Давайте продолжим, чтобы наши классы модели данных соответствовали NSSecureCoding.

Здесь довольно много изменений, давайте пробежимся по некоторым моментам.

  1. Мы делаем наши модельные классы подклассами NSObject, чтобы их можно было сериализовать. Кроме того, мы делаем их соответствующими протоколу NSSecureCoding;
  2. Мы устанавливаем статическое свойство supportsSecureCoding в значение true;
  3. Мы используем decodeObject(of: forKey:) для декодирования объекта при извлечении данных из Core Data;
  4. Поскольку CGPoint не соответствует протоколу NSSecureCoding, мы конвертируем его в NSString и затем кодируем. Когда мы декодируем его, мы затем конвертируем его обратно в CGPoint;
  5. Поскольку Path — это пользовательский класс, нам нужно включить тип Path в массив ожидаемых классов, которым должен соответствовать декодируемый объект.

Теперь мы привели наши классы моделей в соответствие с NSSecureCoding. Давайте перейдем к созданию подкласса NSSecureUnarchiveFromDataTransformer для нашего атрибута drawings, чтобы он знал, как преобразовать свое значение из NSData в правильные типы данных при извлечении из Core Data.

Здесь мы добавляем класс Paths в массив allowedTopLevelClasses, потому что это класс верхнего уровня в процессе преобразования значений. Мы также создаем статический метод с именем Register, который позволяет нам зарегистрировать пользовательский преобразователь в нашем приложении, и это то, что мы будем делать дальше.

Давайте откроем файл AppDelegate.swift и внесем следующие изменения, чтобы зарегистрировать наш пользовательский преобразователь:

Затем мы возвращаемся в наш редактор модели Core Data и указываем Transformer и CustomClass для атрибута drawings:

После всех этих шагов наше приложение может сохранять рисунки пользователя в Core Data.