Есть 3 основных этапа основных данных: моделирование, сохранение и выборка. Мы начинаем с создания модели данных с объектами, которые мы хотим сохранить. Затем мы сохраняем экземпляры тех сущностей, которые находятся в нашем контексте управляемого объекта. Затем мы можем получить эти сохраненные экземпляры (управляемые объекты) из нашего контекста. При желании мы можем фильтровать и сортировать эти извлеченные объекты.

ПРИМЕЧАНИЕ. В этом посте предполагается, что вы уже настроили стек Core Data. Если вы этого не сделали, возможно, вам будет полезно взглянуть на статью Код Apple Core Data Boilerplate.

МОДЕЛИРОВАНИЕ

Моделирование — первая и самая важная часть Core Data. Плохое моделирование сделает работу с остальными базовыми данными сложной задачей. Так что делайте это с самого начала. Так что же мы подразумеваем под моделированием? Ну, моделирование наших сущностей… что очень похоже на то, как мы моделируем наши классы. Прежде чем мы рассмотрим, как это выглядит, давайте начнем с создания файла модели данных.

Итак, начните с открытия окна «Новый файл», выбрав «Файл» > «Создать» > «Файл» или нажав Cmd+N. Затем в iOS перейдите в Core Data и выберите Модель данных.

Дайте ему имя и сохраните его. Теперь, когда вы откроете его, вы получите окно, похожее на это:

Прежде чем мы начнем моделировать объекты, давайте посмотрим, как мы будем моделировать объект Dog.

Обратите внимание, что у нас есть 4 свойства: имя, порода, вес и владелец. Теперь давайте создадим объект Dog.

Мы добавляем новый объект, либо нажав кнопку «Добавить объект» внизу, либо перейдя в «Редактор» > «Добавить объект».

Это даст нам пустую сущность с «сущностью» в качестве имени по умолчанию. Вы можете дважды щелкнуть по нему, чтобы изменить имя. Мы называем объекты так же, как классы, в PascalCase (первая буква каждого слова заглавная).

Итак, у нас есть Сущность Собаки. Теперь нам нужно добавить свойства. Обратите внимание на три таблицы справа.

Вы можете думать об атрибутах как об общем свойстве. Фактически они станут свойствами управляемых объектов. Это данные сущности. Итак, если мы хотим добавить наши свойства, мы должны начать с добавления атрибутов.

Примечание. Поскольку атрибуты становятся свойствами управляемых объектов, вы не можете называть свои атрибуты некоторыми вещами, такими как «описание», поскольку NSObject уже имеет свойство описания, поэтому ваш управляемый объект унаследует его.

Чтобы добавить атрибут, либо нажмите кнопку + под таблицей атрибутов, либо кнопку «Добавить атрибут» в правом нижнем углу, либо перейдите в «Редактор» › «Добавить атрибут».

Как и раньше, он получит имя по умолчанию и тип undefined. Так что дайте ему имя и выберите тип из выпадающего списка. Мы именуем атрибуты так же, как и свойства, в верблюжьем регистре (первая буква каждого слова заглавная, кроме первого слова). Кстати, вы НЕ можете оставить тип неопределенным. Вы получите ошибки компилятора.

NSUIntegers можно сохранить как любой из целочисленных типов. Число зависит только от того, насколько велик диапазон значений. NSUIntegers будет иметь диапазон Integer 32. Просто имейте в виду, что все числа хранятся как NSNumbers. Двоичные данные для хранения изображений, аудио и т. д. Transformable предназначен для пользовательских типов и выходит за рамки этого поста. Остальные типы говорят сами за себя.

Итак, давайте добавим некоторые свойства:

Круто, так что это было легко. А как насчет свойства owner? Как мы это добавим? Это объект Person. Ну, мы начнем с того, что превратим эту сущность Person в Entity. Итак, создайте новую сущность и назовите ее Person. Затем присвойте ему атрибут String для имени. Теперь давайте вернемся к сущности Dog и немного поколдуем.

Помните ту таблицу отношений? Ну, это другая наша собственность. Свойства, являющиеся типом другого объекта, считаются отношениями, а не атрибутами. Если подумать… имя, порода и вес — все это атрибуты собаки, но можно ли считать атрибутом владельца? Скорее хозяин собаки — это отношения.

Чтобы добавить связь, либо нажмите кнопку + под таблицей связей, либо нажмите и удерживайте кнопку «Добавить атрибут» в правом нижнем углу и нажмите «Добавить связь», либо перейдите в «Редактор» › «Добавить связь».

Это даст вам имя по умолчанию. Поэтому вставьте «владелец» вместо имени. Пункт назначения в значительной степени спрашивает, какой тип используется для владельца или, другими словами, какая сущность упоминается как «владелец». Так что, конечно, мы выберем Person.

Последняя часть называется Inverse, что означает обратное отношение. Обратная связь — это в значительной степени связь с точки зрения другой стороны. Так что, если владелец собаки — Человек, то с точки зрения владельца будет обратное: собака человека — это собака.

Обратите внимание, что на данный момент в раскрывающемся списке Inverse нет параметров. Это потому, что мы должны установить обратное отношение, прежде чем установить его как обратное. Итак, мы перейдем к сущности Person и добавим отношение собаки, которое указывает на сущность Dog.

Обратите внимание, что теперь отношение Inverse имеет опцию владельца. Выберите это, потому что человек является владельцем собаки человека. Звучит грубо, но на самом деле не так уж и плохо. Теперь, когда вы вернетесь к своей сущности Dog, она должна автоматически выбрать собаку в качестве инверсии для владельца. Если это не так, и он по-прежнему говорит «Нет обратного», вы можете выбрать его вручную.

Мы еще не закончили. Если подумать, у нашей собаки может быть хозяин, но у нашего владельца может быть несколько собак.

Итак, у нашей собаки с одним владельцем отношения «один к одному», а у человека, имеющего нескольких собак, — отношения «один ко многим». По умолчанию наши отношения Один к Одному. Если вы хотите изменить его, пока отношение выбрано, откройте панель «Утилиты» справа и щелкните третий значок, инспектор модели данных. Перейдите к типу и измените тип на «Многим».

Прохладный! Итак, мы успешно смоделировали две наши сущности. Теперь о добавлении и сохранении.

СОХРАНЕНИЕ

Теперь, чтобы сохранить наши управляемые объекты, нам сначала нужно иметь управляемые объекты для сохранения. Итак, давайте сделаем несколько. Для краткости мы не будем рассматривать подклассы NSManagedObject.

Итак, как мы создаем экземпляры наших сущностей?

Для простоты давайте поработаем с нашей реализацией AppDelegate внутри application:didFinishLoadingWithOptions.

В отличие от создания экземпляров обычных объектов, когда мы хотим создать экземпляр Entity, мы создаем экземпляр NSManagedObject. Вместо выделения и инициализации мы создадим новый экземпляр, используя описание объекта. Мы даем ему имя объекта и контекст управляемого объекта, в который мы хотим его поместить.

Теперь, чтобы установить эти атрибуты. К сожалению, в отличие от других объектов, мы не можем использовать точечный синтаксис с NSManagedObjects. Если вы хотите использовать точечный синтаксис, вам придется подклассировать его. Чтобы установить значения атрибутов без создания подкласса, используйте метод setValue:forKey.

Итак, давайте установим значения для этих атрибутов. Давайте предположим, что я создал еще одну сущность для Person под названием shaggy.

Прохладный. Итак, теперь в нашем приложении у нас есть управляемый объект Dog и управляемый объект Person. Мы вставили их в контекст управляемых объектов, и, как следует из названия, нашими управляемыми объектами управляет Core Data. Круто, значит, у нас все хорошо, верно? Неа. Если вы сейчас закроете приложение и откроете его снова, два наших управляемых объекта исчезнут. Они были в нашем контексте, так что дает!? Ну, мы никогда не сохраняли контекст. Итак, теперь давайте перейдем к главному вопросу: как, черт возьми, вы сохраняете контекст?

Да, это так. Это так просто. Однако мы могли бы пойти немного дальше. Метод save возвращает BOOL, указывающий, успешно ли выполнено сохранение. Мы можем использовать оператор if, чтобы зарегистрировать успешность сохранения.

Это может привести к непростым результатам, поскольку метод save завершается ошибкой, если в контексте нет изменений для сохранения. Core Data не видит смысла тратить время на запись данных на диск, если изменений нет. Поэтому, чтобы быть более точным, мы вложим этот код в другой оператор if, проверяющий, есть ли изменения в нашем контексте.

И вуаля, мы сохранили наши объекты. Теперь, когда мы в следующий раз откроем наше приложение, эти объекты сохранятся. К сожалению, их нет в нашем приложении… они в нашем хранилище. Итак, теперь нам нужно найти способ получить сохраненные объекты, чтобы мы могли их использовать. Вперед к получению!

ПОЛУЧЕНИЕ

Есть 3 способа сделать запросы на выборку в коде:

  1. Первый способ - использовать назначенный инициализатор и передать имя сущности
  2. Второй способ — использовать метод класса для возврата экземпляра NSFetchRequest для заданного имени объекта.
  3. Наконец, мы можем сделать обычный alloc-init. Однако это обременительно, так как вам придется создать NSEntityDescription для передачи в метод setEntity запроса на выборку.

Вы также можете настроить запрос на выборку в редакторе модели данных, создав шаблон запроса на выборку. Мы рассмотрим это позже.

Возвращаясь к нашим трем запросам на выборку… Независимо от того, какой из них мы используем, мы получим одинаковые результаты. Итак, мы получили объекты собаки 3 раза? Нет. Мы получили их НОЛЬ раз. Это потому, что NSFetchRequest — это именно то, на что это похоже, запрос на получение чего-либо. Чтобы на самом деле получить эти вещи, вы должны запустить запрос или, в данном случае, выполнить.

Игрок основного стека данных, который будет выполнять этот запрос на выборку, является нашим контекстом управляемого объекта. Мы будем использовать очень прямолинейный метод имени: executeFetchRequest: error: … Видите? Простой. Поскольку все запросы на выборку по сути одинаковы, для простоты мы будем использовать первый.

Круто, теперь мы взяли все сущности Dog в нашем контексте управляемых объектов и поместили их в массив fetchedDogs. Ироничное имя, да?

Именно так вы получаете все управляемые объекты с определенным описанием объекта. Теперь предположим, что в нашей базе данных было МНОГО собак, и мы хотели заполучить Скуби-Ду, но почему-то забыли его имя (как???). Мы знаем, что он немецкий дог. Есть ли способ, которым мы можем получить только немецких догов из нашей базы данных собак?

Ну да. Введите предикаты. NSPredicates — это небольшие полезные объекты, позволяющие фильтровать коллекцию. Я не буду подробно рассказывать о том, как они работают, поэтому не стесняйтесь прочитать о них, прежде чем продолжить.

Итак, предполагая, что вы знаете, как работают предикаты NSP, мы просто создадим предикат, который фильтрует на основе «породы» и проверяет, является ли он «немецким догом» (без учета регистра). Наконец, мы добавляем его в запрос на выборку с помощью метода setPredicate.

Теперь ваш запрос на получение будет получать только датские доги.

Хорошо, так это здорово! Итак, скажем, теперь у нас есть подсказка. Мы знаем, что его имя начинается с буквы S! … или, может быть, это была буква D? Теперь, в случае, если мы соберем 100 немецких догов, будет очень сложно пройти их все. Было бы здорово, если бы мы могли отсортировать их по алфавиту, чтобы мы могли сразу перейти к собакам с именами, начинающимися с D или S? Введите дескрипторы сортировки.

Еще раз, я не буду вдаваться в то, как работают дескрипторы сортировки, но если вы знаете, как это сделать (почитайте об этом), это так же просто, как предикат. Вы просто создаете свои дескрипторы сортировки и передаете массив дескрипторов сортировки. Почему массив? Таким образом, вы можете иметь более конкретную сортировку. Например, вы можете расположить всех своих собак по породам, а затем отсортировать всех собак определенной породы в алфавитном порядке.

Итак, теперь мы получили все наши объекты, управляемые собаками, которые являются немецкими догами, и расположили их в алфавитном порядке. Потрясающий!

Прежде чем мы закончим этот пост, давайте посмотрим, как мы можем использовать шаблоны запросов на выборку, чтобы помочь нам с более чистым кодом. Как вы можете понять по названию, это шаблон, из которого вы можете сделать запрос на выборку.

Итак, чтобы создать шаблон запроса на выборку, мы начинаем с нашего редактора модели данных. Чтобы добавить его, мы можем либо долго нажимать кнопку «Добавить объект» внизу, а затем нажать «Добавить запрос на получение», либо мы можем перейти в «Редактор»> «Добавить запрос на получение».

Итак, начнем с того, что дадим нашему шаблону имя. Назовите его как-нибудь описательно, чтобы его было легко понять в коде. Теперь обратите внимание на область, где написано «Принести все». Здесь мы можем выбрать, какую сущность мы хотим получить. Обратите внимание на область под ним. Это область условий предиката. Мы можем добавить новое условие, нажав кнопку + справа.

Это даст вам последовательность из 3 частей для условия:

АТТИБУТ — ОПЕРАТОР — ЗАПРОС

Так что вы бы выбрали оператора (в данном случае породу)

Мы бы выбрали оператор (в данном случае is)

А потом заканчиваем выражение (В данном случае Немецкий дог)

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

Мы используем метод управляемой объектной модели (не контекста) fetchRequestFromTemplateWithName:substitutionVariables:, чтобы выполнить запрос на выборку. Мы просто указываем имя шаблона и пустой словарь для substitutionVariables, так как он не может быть нулевым. И мы получили наш Предикат! В качестве бонуса предикаты, которые мы создали в Редакторе модели данных, добавляются автоматически! К сожалению, нам все равно придется добавлять дескрипторы сортировки по старинке (будем надеяться, что Apple в конечном итоге добавит это в редактор).

Теперь будьте осторожны, вы также можете использовать fetchRequestTemplateForName:, но он возвращает неизменяемый запрос на выборку. Это означает, что если вы попытаетесь установить дескриптор сортировки для запроса на выборку, полученного с помощью этого метода, ваш проект не будет скомпилирован, и вы получите следующее:

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

Вот как вы используете шаблон запроса на выборку. Это может быть полезно для поддержания чистоты вашего кода. И на этом мы официально закончили с Fetching.

TLDR

  • Мы начинаем с моделирования, добавляя файл модели данных в наш проект.
  • Добавляем Entities и присваиваем им атрибуты
  • Устанавливаем любые отношения между Сущностями
  • Затем мы создаем экземпляры наших управляемых объектов.
  • Для этого мы используем метод NSEntityDescription insertNewObjectForEntityForName:inManagedObjectContext:
  • После создания и настройки наших управляемых объектов мы вызываем сохранение нашего контекста, вызывая метод NSManagedObjectContext save.
  • Теперь, когда мы хотим получить наши управляемые объекты из NSManagedObjectContext, мы делаем запрос на выборку.
  • Мы можем инициализировать его соответствующим именем Entity.
  • При желании мы можем добавить предикат и массив дескрипторов сортировки.
  • Чтобы запустить запрос на выборку, мы используем метод NSManagedObjectContext executeFetchRequest:
  • Мы можем использовать редактор модели данных, чтобы создать шаблон запроса на выборку, и использовать fetchRequestFromTemplateWithName:substitutionVariables:, чтобы сделать запрос на выборку в коде.

И это основа Core Data. Извините за ужасно длинный пост. Надеюсь, вы извлекли из этого какую-то ценность.

Отсюда вы можете проверить сообщение о подклассах NSManagedObject.