Как добавить core data в готовое приложение
В прошлой статье мы изучали стек технологий 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 [необязательными].
Тип атрибута
Тип атрибута имеет важное значение по нескольким причинам. Он сообщает 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)]. Мы сделали что-то неправильно?
Граф модели данных
Этот стиль показывает объектный граф, который мы создали до этого. Он показывает нам сущности, которые мы создали, их атрибуты и взаимосвязи. Одним из наиболее полезных свойств, однако, является визуальное представление взаимосвязей между сущностями в модели данных. Линия со стрелкой на каждом конце, соединяющая 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 .
Поскольку Core Data, несомненно, кажется сложной для многих новых разработчиков, я решил попытаться объяснить работу простыми словами.
12 месяцев назад
Этот пост предназначен для новичков в разработке на платформах Apple. Поскольку Core Data, несомненно, кажется сложной для многих новых разработчиков, я решил попытаться объяснить работу простыми словами.
Если вы посмотрите в Интернете определение, вы в Apple Developer сможете найти что-то вроде такого:
Или может быть что-то вроде этого в Wiki:
Это мало что объясняет.
Зачем нам нужно что-то вроде Core Data?
Приложениям часто требуется хранить большие объемы важных данных. Типичным примером может быть что-то вроде приложения для заметок, мессенджера или практически любое приложение, которое загружает данные с сервера и хочет избежать потенциально долгой загрузки тех же данных снова.
Хотя вы можете хранить данные для основного приложения для заметок в виде простого файла с помощью Codable, этот подход плохо масштабируется. Для каждого небольшого изменения вам нужно снова перезаписывать весь файл. Если вы позже решите изменить свою модель данных (в данном случае вашу структуру/класс Codable), вам нужно быть очень осторожным, иначе ваши пользователи могут легко потерять данные, так как их файл структурирован в соответствии со старым определением, а вы его изменили. Как вы, вероятно, знаете, UserDefaults не следует использовать для хранения больших объемов данных, а скорее для настроек пользователя.
Чтобы хранить и извлекать большие объемы данных, вам нужна база. Обычно стандартные базы данных требуют своего собственного языка (SQL) для извлечения и сохранения данных. Если вы хотите напрямую использовать базу данных из вашего кода Swift, вам нужно будет вручную создать команды SQL, выполнять их, а затем вручную анализировать результат.
К счастью, у нас есть Core Data, которая обрабатывает все это за нас.
Что такое Core Data на самом деле?
Я думаю, что в самых простых терминах Core Data можно понимать как прослойку между «сырой» базой данных и вашим кодом Swift. Внутри она использует базу данных SQLite, которая, по сути, представляет собой один специальный файл, содержащий логику и данные. Для нас важно то, что мы можем работать только с Core Data и экземплярами классов Swift, которые в Core Data сохраняют и извлекают данные из базы.
«Граф объектов» и другие причудливые описания означают то, что Core Data может интеллектуально контролировать ваши классы, отслеживать изменения, и когда вы вызываете save в контексте объекта, эти изменения сохраняются в базе данных. Фреймворк также управляет миграцией, что довольно часто встречается в мире баз данных SQL. Поскольку эти базы данных имеют строго определенную структуру, в соответствии с которой они сохраняют данные, если вы решите изменить свою модель (это означает такие вещи, как добавление/удаление свойств в ваших классах, переименование свойств или добавление отношений), вам необходимо выполнить миграцию. Это процесс, который обеспечивает актуальность структуры базы данных (называемой «схемой») и ее готовность к работе с новыми определениями модели. Это означает, что если у вас есть имя свойства, то в базе данных есть столбец для сохранения этой информации.
Если бы вы использовали базу данных напрямую, вам пришлось бы выполнять эти миграции вручную, и вы могли бы действительно испортить базу данных. К счастью, Core Data может обрабатывать множество изменений с помощью автоматической миграции, что означает, что вам не нужно ничего делать.
Помимо получения и сохранения данных, миграции, есть еще одна важная вещь, которую Core Data делает за вас, и это отношения между объектами. Если у вас есть какой-то объект, например Папка, и в нем есть массив заметок, то вам необходимо сохранить эту информацию вместе с самой папкой и заметками. В мире SQL вам нужно будет определить особый вид ключей, которые будут связывать их вместе. Если вы устанавливаете отношения через Core Data, вы получаете все это автоматически. Таким образом, вы можете работать со связанными объектами, не думая о создании и управлении отношениями вручную.
Есть масса вещей, в которые мы могли бы углубиться, но поскольку это введение, давайте пропустим все и рассмотрим части, из которых состоят Core Data.
Части Core Data
В этом разделе мы рассмотрим основными частями Core Data, с которыми вы столкнетесь, когда начнете их использовать.
.xcdatamodeld
Это файл модели Core Data, обычно называемый как-то вроде «Модель», «База данных» или как текущий проект. По сути, это шаблон для Core Data, который сообщает ему, какие объекты мы планируем хранить, каковы их свойства и отношения между ними.
Если вы откроете его в Xcode, вы сможете, среди прочего, добавлять сущности и настраивать их свойства. Затем эти сущности превращаются в соответствующие классы, которые наследуются от NSManagedObject. Вы можете либо позволить Xcode сгенерировать их, либо создать свой собственный файл, что я всегда и делаю и вам рекомендую.
Xcode не позволит вам увидеть исходный файл, но вы можете найти его на диске и открыть в любом текстовом редакторе. Если вы выберете тот, который поддерживает синтаксис XML, его будет легче читать.
NSManagedObject
Все классы Core Data являются подклассами этого класса, что позволяет им работать с Core Data. Это стандартные классы Swift с несколькими дополнительными аннотациями. Выше мы видели сущность Joke, представленную в модели, а здесь она представлена как класс:
Это также позволяет Core Data заполнять эти свойства по мере необходимости, они могут быть пустыми, без нашего ведома или заботы об этом. Сущности Core Data часто возвращаются как “faults”, что означает, что это пустые объекты и данные заполнятся тогда, когда ваше приложение запросит их. Это отличная оптимизация. Если вы получаете 1000 объектов из Core Data, а ваша коллекция отображает только 20 из них без пользовательской прокрутки, для остальных объектов данные не обязательно должны присутствовать в памяти.
NSPersistentContainer
Это «основной» класс, охватывающий работу с Core Data. В его обязанности входит загрузка модели данных (файл .xcdatamodeld) и, возможно, реагирование, если он не может ее найти или отсутствуют классы для определенных сущностей.
Обычно вы инициируете его с именем файла модели, а затем вызываете loadPersistentStores для загрузки.
Он также имеет очень важное свойство viewContext, которым является NSManagedObjectContext, и мы рассмотрим его дальше.
NSManagedObjectContext
Этот класс позволяет нам получать данные из базы данных, а также сохранять их. Вы получаете данные вызывая fetch в этом контексте, для чего требуется экземпляр NSFetchRequest. Ваше приложение обычно имеет один основной контекст (которого может хватить во многих случаях). Этот контекст имеет связанные сущности, поэтому он может отслеживать изменения и сохранять их при необходимости.
Это также причина, по которой вам нужно передать контекст в инициализацию NSManagedObject. Таким образом вы связываете объект с контекстом, который будет им управлять. Помимо уже упомянутой выборки, вы, вероятно, будете часто использовать метод сохранения, а также есть свойство hasChanges для проверки перед сохранением.
Прежде чем мы продолжим, нам нужно вернуться к NSPersistentContainer. Мы можем вызвать для него performBackgroundTask, что даст нам замыкание с фоновым NSManagedObjectContext в качестве входного параметра. Таким образом, мы можем довольно легко выполнить фоновую работу с базой данных, не влияя на видимую производительность. Вы можете использовать выборку в этом фоновом контексте, изменять сущности и затем сохраняя их.
NSFetchRequest
Экземпляр NSFetchRequest сообщает NSManagedObjectContext, что вы хотите и каким образом. Это общий для NSManagedObject, который позволяет нам указать, какой тип сущности мы хотим получить.
Затем вы можете настроить фильтр (используя NSPredicate), а также сортировку (используя массив экземпляров NSSortDescriptor). В базовых случаях нужна только сортировка, потому что вы, вероятно, хотите показать пользователю все данные.
Есть несколько сложных вариантов использования, но я думаю, что пока этого достаточно.
NSPredicate
Это «метод фильтрации» в мире Core Data. У него есть слабое место, потому что вам нужно указать его как строку специального формата, и если вы сделаете ошибку, вы узнаете об этом только при запуске приложения.
Вот очень простой пример:
Приведенный выше предикат будет фильтровать сущности Note, для которых свойство wasDeleted имеет значение false. Пометка элементов как удаленных вместо их удаления называется «мягким удалением» и очень полезна. Вы можете легко реализовать что-то вроде функции «Корзина», а также, если вы обрабатываете облачную синхронизацию, это, по сути, необходимо для отслеживания удаленных элементов.
Мы могли бы переписать приведенный выше предикат по-разному:
Это короче, но если мы переименуем wasDeleted в будущем, это перестанет работать.
Другой, еще более короткий вариант:
NSSortDescriptor
С экземпляром этого класса мы можем сообщить NSFetchRequest, как сортировать наши сущности. Вы можете предоставить массив, и порядок будет определять, как элементы будут отсортированы по нескольким свойствам.
Это базовый пример, который сортирует объекты Note по их заголовку. Если бы мы хотели сначала показать избранные заметки, мы бы передали этот массив в NSFetchRequest
Сначала мы получали все избранные заметки, отсортированные по заголовку, а затем все остальные, также отсортированные по заголовку.
NSFetchedResultsController
Обычно сокращаемый до «FRC», этот класс в основном создан для UITableView и UICollectionView. Он управляет извлечением данных из базы данных за вас, а также сообщать вам количество разделов и элементов в определенных разделах, которые необходимы для реализации источников данных.
Начиная с iOS 13, я бы рекомендовал использовать различные источники данных, которые значительно упрощают работу с этими представлениями коллекций и FRC. Но это тема для другого дня.
Я надеюсь, что этот пост помог вам понять основы Core Data, и если что-то отсутствует или неясно, пожалуйста, дайте мне знать в Twitter, и я сделаю все возможное, чтобы улучшить это.
Спасибо за прочтение. А теперь идите и создайте что-нибудь с Core Data! :-)
C ore Data – фреймворк для работы с базой дынных в приложениях. С его помощью можно хранить и управлять данными. Я не часто его использовал, и у меня никак не было времени, чтобы разобраться с ним. Но на этих выходных время пришло.
Чтобы разобраться в принципах работы с Core Data, я хочу написать небольшое туду приложение. Звучит банально, но в этом приложении список дел можно будет сохранять как изображение и делать его заставкой на экране.
Начну с создания нового проекта. Желательно, отметить галочку как указано на картинке. В этом случае в файлах AppDelegate.swift и SceneDelegate.swift` сгенерируется дополнительный код и добавится специальный файл Memo.xcdatamodeld. Memo – это название моего проекта.
В файле SceneDelegate.swift в функции scene появилась новая строчка
Эта функция возвращает контекст управляемого объекта(managed object context). Контекст управляемого объекта похож на блокнот, который хранится в оперативной памяти. Это место, где объекты создаются, выбираются, обновляются, удаляются и сохраняются обратно в постоянное хранилище на устройстве.
Ниже еше одна интересная строчка кода:
Тут создается ContentView , который потом передается в конструктор контроллера. Но что это за environment ?
Перед тем, как запустится, наше корневое представление ContentView – в окружении установится новый параметр managedObjectContext с контекстом, который мы только что создали. Окружение – это место где хранятся различные системны параметры, например локаль календаря, цветовая схема и т.д. Все эти параметры хранятся по разным ключам. И теперь наш контекст тоже хранится там по ключу managedObjectContext .
Теперь каждое представление может использовать “блокнот” для работы с объектами.
Определимся со структурой данных которыми буду манипулировать в приложении. Для этого в файл Memo.xcdatamodeld добавлю новую сущность Todo . Для этого надо кликнуть на большой жирный плюс Add Entity
Теперь к новой сущности добавляем нужные аттрибуты. Для простого туду достаточно добавить text , done и поля id с типом UUID(это поле будет использоваться как уникальный идентификатор объекта).
Генерировать код в ручную не обязательно. Можно оставить значение Class Definition в поле Codegen и успокоится. Но я выберу Manual/None – это позволит сгенерировать файлы в папке проекта и посмотреть что там будет.
Теперь генерирую файлы.
Получается пара новый файлов в проекте: Memo+CoreDataClass.swift и Memo+CoreDataProperties.swift . В Memo+CoreDataClass.swift описан сам объект. А в Memo+CoreDataClass.swift описываются его свойства.
Замечу, что еще один плюс генерации классов в ручную – возможность вносить разные дополнения, которые недоступны при работе только через интерфейс для .xcdatamodeld . Например, можно сделать нужные поля как enum . Или добавить реализацию нужного интерфейса.
Нужно убедиться, что блок предпросмотра имеет доступ к параметру окружения managedObjectContext как и все приложение.
Теперь к интерфейсу самого приложения. Делать его буду стильно, модно и молодежно с помощью SwidtUI. Нужен заголовок, список с задачами, текстовое поле и кнопка для добавления новых задач. В ContentView добавил такой код:
Теперь подружу интерфейс с Core Data.
Пока у меня ничего не сохранятся и не выводится. Чтобы сохранить новую задачу, нужно иметь доступ к контексту управляемого объекта. И тут становится понятным, зачем мы добавляли контекст в окружение. К нему можно получить доступ, используя свойство @Environment внутри нашего ContentView .
И теперь можем написать код, который создает новый объект Task . Этот код нужно поместить в экшене кнопки "Add Task"
И теперь с помощью managedObjectContext сохраняем данные на устройстве.
Чтобы прочитать сохраненные данные из хранилища, воспользуюсь свойством @FetchRequest , которое добавлю в ContentView . С помощью этого свойства очень легко манипулировать сохраненными данными.
Это, конечно, круто что можно одной строчкой объявить переменную и сразу указать что она заполнится данными их хранилища. Но как пом не, это не очень очевидно и читать такие объявления в чужом коде – самая настоящая боль. И это еще не используется параметр predicate в свойстве @FetchRequest который может сделать все объявление нечитаемым.
Теперь отредактирую отображение списка задач, добавлю цикл по todos с помощью ForEach
Этот код у меня не захотел сразу работать.
Чтобы избавиться от этих ошибок – нужно добавить интерфейс Identifiable для класса Todo в файле Todo+CoreDataProperties.swift
У нас уже есть аттрибут id , поэтому после добавления интерфейса все заработает как нужно.
Запускаем эмулятор и добавляем новые задачи.
Редактирование и удаление
Отлично! Можно добавлять новые задачи. Осталось добавить возможность помечать их как выполненными и удалять. Для этого изменю блок с кнопкой – добавлю условие и сделаю две кнопки.
Теперь в несколько строчек реализуем выполнение задачи
В приложениях на SwiftUI стало еще проще использовать Core Data. Всю основную магию за вас делает свойство @FetchRequest . Но если вы новичек в Swift и iOS, то вам стоит подробнее изучить как работает выборка объектов из хранилища и что такое предикаты.
- При показе detail view, переместить данные из атрибута name в текстовое поле.
- При выходе с detail view, переместить данные из текстового поля в атрибут name.
- Сохранить managed object context.
Тут помогут методы viewWillAppear и viewWillDisappear.
Split-view контроллеры на iPad позволяют поместить master view в левой части экрана, а правая часть содержит detail view controller и его view. Т.е. обходится без swapping-а вьюх. Поэтому контролировать перемещение данных с помощью viewWillAppear и viewWillDisappear не получится.
Когда iPad держится вертикально вверху появляется кнопка по нажатию на которую появляется pop-over с master view контроллером.
Методы setDetailItem и configureView вызываются в DetailViewController когда устанавливается новый detail item или view нуждается в обновлении.
В случае с UITableView можно использовать didSelectRowAtIndexPath.
DetailViewController содержит переменную detailItem. Её значение устанавливается в MasterViewController.m в методе didSelectRowAtIndexPath:
NSManagedObject *selectedObject =
[[self fetchedResultsController] objectAtIndexPath:indexPath];
self.detailViewController.detailItem = selectedObject;
Свойство detailItem объявлено в DetailViewController.h:
@property (strong, nonatomic) id *detailItem;
Т.к. мы точно знаем что detailItem будет класса NSManagedObject, то можно указать это явно:
@property (strong, nonatomic) NSManagedObject *detailItem;
Если вы хотите отсортировать список в master view, то это делается при создании fetchedResultsController в MasterViewController.m.
Можно еще изменить заголовок Detail в DetailViewController.m в методе initWithNibName:
Читайте также: