Core Data и Swift: Модель данных
() translation by (you can also view the original English article)
Введение
В прошлой статье мы изучали стек технологий Core Data - сердце любого приложения, использующего Core Data. Мы рассмотрели контекст управляемого объекта, координатор постоянного хранилища и управляемую объектную модель.
Эта статья сфокусирована на модели данных Core Data. Мы подробно рассмотрим редактор модели данных, предлагаемую Xcode, а также пробежимся по сущностям, атрибутам и взаимосвязям.
Необходимый минимум
То, что я расскажу в этой серии про Core Data, применимо к iOS 7+ и OS X 10.10+, но основное внимание будет уделяться iOS. В этой серии я буду работать с Xcode 7.1 и Swift 2.1. Если вы предпочитаете Objective-C, то я рекомендую прочитать мои предыдущие статьи про Core Data.
1. Редактор модели данных
Начните с загрузки проекта из предыдущей статьи или клонируйте репозиторий с GitHub. Откройте проект в Xcode и, в Навигаторе проекта (Project Navigator), найдите Core_Data.xcdatamodeld. Xcode автоматически покажет редактор модели данных при выборе модели данных в проекте.



2. Сущности
Прежде чем мы рассмотрим пользовательский интерфейс редактора, нам нужно создать какую-нибудь сущность для работы с ней. В нижней части редактора модели данных нажмите кнопку Add Entity (Добавить сущность). Будет добавлена сущность с именем Entity. Она будет показана в разделе Entities, в левой части редактора модели данных. Измените имя сущности на Person, кликнув двойным щелчком на ней в разделе Entities.



Вас наверно интересует: Что еще за сущность? Возвращаясь к аналогии с базой данных, сущность сравнима с таблицей базы данных. Когда вы выбираете сущность Person, вы видите, что она может иметь атрибуты, взаимосвязи и получаемые свойства (fetch-свойства). Не беспокойтесь о получаемых свойства сейчас, они относятся к более продвинутым функциям фреймворка.
3. Атрибуты
Добавьте атрибут для сущности Person, кликнув по кнопке с плюсом в нижней части таблицы атрибутов (Attributes). Дважды кликнув по имени атрибута установите ему имя first. Из выпадающего меню «Type» выберите тип String. Если сравнивать это с таблицей базы данных, то таблица Person сейчас имеет колонку first с типом String.



Однако, я не хотел бы вас запутать, сравнивая сущности с таблицами базы данных, но так легче понять, что представляют из себя сущности и атрибуты. Фактически, если вы используете базу данных SQLite как хранилище вашего приложения, Core Data создаст для вас таблицу, чтобы хранить данные сущности Person. Но это не то, что нас волнует, и не стоит беспокоиться об этом. Запомните: Core Data - это не база данных.
То же самое касается и взаимосвязей. Нам нет необходимости беспокоится о том, как Core Data отслеживает взаимосвязи. Фактически Core Data гарантирует, что взаимосвязи будут загружены только тогда, когда приложение будет нуждаться в них. Мы вернемся к этому в одной из следующей статей в рамках этой серии.
Добавьте еще два атрибута для сущности Person, атрибут last с типом String и атрибут age с типом Integer 16. Какой именно тип вы выберете для чисел сейчас не важно. Это говорит Core Data, как следует структурировать постоянное хранилище и оптимизировать его для повышения производительности.
Параметры атрибутов
Атрибут сущности можно настроить с помощью Data Model Inspector (Инспектор модели данных). Выберите атрибут first сущности Person и откройте инспектор (справа). Инспектор модели данных (Data Model Inspector) позволяет настроить выбранный атрибут. На данный момент мы заинтересованы только в некоторых параметрах: Optional, Attribute Type и Default Value.
Optional
Отметка Optional (необязательный) в параметрах атрибута означает, что атрибут может быть пустым (не заполненным), в том числе для записи. Однако, в нашем примере, мы хотим убедиться, что каждая запись Person [Человек] имеет first name [имя]. Снимите флажок Optional для атрибута first, выбрав его при необходимости. По умолчанию, новые атрибуты являются optional [необязательными].
Маркировка атрибута (при необходимости) будет иметь последствия. Если мы сохраняем запись Person без корректного first [имени], Core Data выдаст сообщение об ошибке. Это означает, что нам нужно быть уверенным, что атрибут записи first установлен перед сохранением.
Тип атрибута
Тип атрибута имеет важное значение по нескольким причинам. Он сообщает Core Data, что хранить и возвращать нам данные нужно в указанном формате. Каждый тип атрибута имеет различный набор настраиваемых параметров. Измените тип атрибута first на Date, чтобы просмотреть настраиваемые параметры для атрибута с типом Date.
Значение по умолчанию
Некоторые типы атрибутов, такие как String и Date, имеют Default Value (значение по умолчанию), которое вы можете задать. Это удобно, например, если атрибут является обязательным, и вы хотите убедиться, что атрибут имеет корректное значение, когда он добавляется в базу данных.
Обратите внимание, что значение по умолчанию используется только при создании новой записи. Если существующий запись Person, например, обновляется, c уже установленным атрибутом first равным nil
, то Core Data не будет перезаполнять атрибут first значением по умолчанию. Вместо этого Core Data выдаст ошибку, потому что мы отметили атрибут first как обязательный.
4. Взаимосвязи
Core Data показывает себя во всей красе, когда вы начинаете работать со взаимосвязями между сущностями. Давайте посмотрим, как это работает, добавив вторую сущность с именем Address [адрес]. Сущность Address имеет четыре атрибута типа String: street [улица], number [номер дома], city [город] и country [страна].
Взаимоотношения между сущностями имеют ряд определяющих характеристик: имя, назначение, количество элементов [связи], обратная взаимосвязь и правило удаления.
Давайте рассмотрим взаимоотношения более подробно, создавая их между сущностями Person и Address.
Name, Destination и Optionality
Создайте связь путем выбора сущности Person и нажмите кнопку с плюсом в нижней части таблицы связей (Relationships). Назовите взаимосвязь address и установите в качестве Destination [назначения] сущность Address. Это означает, что каждая запись о человеке [Person] может быть связана с записью об адреса [address].



Как и атрибуты, взаимосвязи являются optional (не обязательными) по умолчанию. Это означает отсутствие проверку на ошибки в случае, если запись о человеке [person] не имеет связанной с ним записи об адресе [address]. Давайте изменим это, сняв флажок Optional в Инспекторе модели данных (справа).
Обратная взаимосвязь
На данный момент человек [person] может иметь связь с записью об адресе [address]. Однако, если человек [person] имеет, связанную с ним, запись об адресе [address], запись об адресе ничего не знает о записи человека, потому что взаимосвязь на данный момент является односторонней — от Person к Address. Большинство связей в Core Data, однако, являются двусторонними, обе сущности знают о взаимосвязи.
Давайте создадим обратную взаимосвязь от сущности Address к сущности Person, выбрав сущность Address и создав взаимоотношение, назвав его person и установив Person в качестве назначения [destination].



Даже несмотря на то, что мы создали обратную взаимосвязь между Address и Person, Xcode выдает нам несколько предупреждений, сообщая, что "Person.address should have an inverse" [Person.address должна быть инвертирована (inverse)] и "Address.person should have an inverse" [Address.person должна быть инвертирована (inverse)]. Мы сделали что-то неправильно?
Core Data не достаточно сообразителен, чтобы понять, какая из взаимосвязей является обратной взаимосвязью. Это легко исправить. Выберите сущности Person и установить Inverse взаимосвязи address в значение person (взаимоотношение person). Если вы теперь выберете сущность Address, то увидите, что обратная взаимосвязь address уже создана для взаимосвязи person.
Граф модели данных
Когда модель данных прирастает сложностью, взаимосвязями, она может стать запутанной и непрозрачной. Xcode кое-что имеет для этого случая. Редактор моделей данных имеет два вида: table [таблица] и graph [граф]. В правом нижнем углу редактора вы должны видеть переключатель, Editor Style [стиль редактора], который позволяет переключаться между двумя стилями. Нажмите кнопку справа, чтобы переключиться на стиль "граф".



Этот стиль показывает объектный граф, который мы создали до этого. Он показывает нам сущности, которые мы создали, их атрибуты и взаимосвязи. Одним из наиболее полезных свойств, однако, является визуальное представление взаимосвязей между сущностями в модели данных. Линия со стрелкой на каждом конце, соединяющая Person и Address, символизирует их двусторонние отношения.



Связь "Один-ко-многим"
Взаимосвязи, которые мы создавали до этого имели отношение "один-к-одному", т.е. человек [person] может иметь один адрес и наоборот. Однако, вполне возможно, что несколько людей живут по одному адресу. Как бы нам включить эту дополнительную информацию в модель данных?
Количество элементов взаимосвязи указывается либо "один-к-одному", либо "один-ко-многим". Давайте у сущности Address изменим взаимосвязь person установив отношение "один-ко-многим". Выберите взаимосвязь person сущности Address, измените ее имя на persons, чтобы отразить суть отношения "один-ко-многим" и установите для данной взаимосвязи Type в значение To Many в инспекторе (справа).



Имя связи не важно, но оно показывает, что это отношение "один-ко-многим". Обратите внимание, что граф модели данных обновляется автоматически. Конечная точка взаимосвязи сущности Person имеет две стрелки, что символизирует отношение "один-ко-многим".
Связь "Многие-ко-многим"
Подожди минутку. Разве это является невозможным, что человек связан с более чем одним адресом? Человек может иметь рабочий и домашний адреса. Верно? Core Data устраняет эту проблему путем создания отношения "многие-ко-многим". Выберите взаимосвязь address сущности Person, измените ее имя на addresses и установите Type в значение To Many. Граф модели данных покажет обновленную взаимосвязь как линию с двумя стрелками на обоих концах.



Рефлексия взаимосвязей
Способом, которым Core Data реализует взаимосвязи очень гибкий. В взаимосвязи, в виде назначения сущности, может быть даже исходная сущность. Это называется рефлексивной связью. Tакже можно иметь несколько связей одинакового типа с разными именами. Человек, например, может иметь мать и отца. Обе связи рефлексивные с единственным отличием - имя взаимосвязи.
Правила удаления
Что происходит при удалении записи на одном конце взаимосвязи? Если вы думали о Core Data как о базе данных, то ответ будет очевидным. Однако, Core Data - это не база данных.
Предположим, что у вас есть сущность Account с отношением "один-ко-многим" к сущности User. Другими словами один аккаунт [account] может иметь множество пользователей [user], но каждый пользователь принадлежит к одному аккаунту. Что произойдет при удалении пользователя? Что произойдет при удалении аккаунта? В Core Data каждая взаимосвязь имеет правило удаления, которое дает понять, что происходит в этих ситуациях.
Правила удаления гарантируют, что вам не придется беспокоиться о ручном обновлении постоянного хранилища при удалении записи. Core Data заботится об этом, чтобы обеспечить согласованное состояние объектного графа.
Выберите взаимосвязь addresses сущности Person и откройте инспектор (справа). В меню Delete Rule (Правило удаления) имеется четыре варианта: No Action, Nullify, Cascade и Deny.
No Action (Никаких действий)
Если вы выбирите No Action, Core Data не будет обновлять или уведомлять источник записи этой взаимосвязи. Это означает, что исходная запись взаимосвязи продолжает думает, что имеет связь с записью, которая была удалена. Редко, когда вы этого хотите.
Nullify (Аннулирование)
Этот параметр устанавливает назначение взаимосвязи равным null, когда запись удаляется. Это правило удаления установлено по умолчанию. Вы можете применять это правило удаления если, например, взаимосвязь является необязательной.
Cascade (Каскад)
Если взаимосвязь между Person и Address имеет значение Cascade, то удаление записи о человек [person] также удалит все записи об адресах [address], которые связаны с этой записью. Это полезно, например, в случаях когда взаимосвязь является обязательной и запись не может или не должна существовать без этой взаимосвязи. Пользователь, например, не должен существовать, если он не связан ни с какой учетной записью.
Deny (Отказ)
В некотором смысле Deny является противоположностью Cascade. Например, если у нас есть сущность Account, которая имеет отношение "один-ко-многим" с сущностью User, а правило удаления установлено как Deny, то удалить запись Account можно только в том случае, если с ней не связана никакая запись User. Это гарантирует, что не существует записей пользователей [user] без записи аккаунта [account].
Заключение
В этой статье мы подробно рассмотрели модель данных, используемую в приложениях с Core Data. Теперь вы хорошо знакомы с сущностями, атрибутами и взаимосвязями, также вы теперь должны уметь создавать их с помощью редактора модели данных Xcode.
Core Data очень хорош в части управления отношениями и редактор модели данных Xcode позволяет легко создавать и управлять взаимосвязями между сущностями. Взаимосвязи между сущностями - это мощный и простой в настройке инструмент. Правила удаления обеспечивают корректность и согласованное состояние объектного графа Core Data.
В следующей статье мы немного испачкаем наши руки и начнем работу с Core Data. Вы узнаете, как создавать, читать, обновлять и удалять запись, а также хорошо познакомитесь с NSManagedObject
и NSFetchRequest
.