Архитектура, которую вы описали в своем вопросе, хорошо работает с Core Data и CloudKit. Могут быть и другие варианты (например, Firebase, Realm), которые стоит изучить, но, поскольку вы упомянули фреймворки Apple, я ограничусь только ими. Это все из моего собственного опыта, , поэтому ваш пробег может отличаться .
Давайте начнем с упрощенного ответа.
Apple предлагает NSPersistentCloudKitContainer
, который инкапсулирует стек Core Data и отражает постоянное хранилище в частной базе данных CloudKit. Хотя это отличное решение для новых приложений, его нельзя использовать с существующими контейнерами CloudKit. «Core Data владеет схемой CloudKita, созданной из модели Core Data. Существующие контейнеры CloudKit несовместимы с этой схемой». Но это все еще может быть путь, который стоит изучить, и есть много доступных ресурсов:
Теперь, разобравшись с этим, давайте углубимся в некоторые особенности.
До NSPersistentCloudKitContainer
приложения должны были управлять синхронизацией и хранилищем между Core Data и CloudKit фреймворков. Хотя это может показаться непосильной задачей, с ней можно справиться. При приближении к решению необходимо иметь в виду несколько вещей:
Лучше всего рассматривать ваши хранилища CloudKit как источник истины .
Важно поддерживать уникальный идентификатор между записью Core Data и записью CloudKit.
В первую очередь ваше приложение / пользовательский интерфейс должны управляться из хранилища Core Data .
Обработка задач - например, создание рецептов, сохранение рецептов, обновление рецептов - поскольку Operation
s может быть полезным.
CloudKit
Открытый / частный / общий доступ - это основа функционирования CloudKit. Контейнер CloudKit имеет три базы данных (CKDatabase
):
privateCloudDatabase : для чтения владельцем, доступ для записи владельцем. Не отображается для вас через Портал разработчика.
publicCloudDatabase : доступно для чтения всем, доступно для записи владельцем. Может быть заблокирован по ролям и виден вам через портал разработчика.
sharedCloudDatabase : доступно для участников общего доступа (CKShare
), но не видны вам.
Эта структура хорошо согласуется с вашим желанием разделить публикуемые c и личные / пользовательские данные.
Подписки (CKSubscription
) можно настроить в базах данных, чтобы уведомлять вас о произошедших изменениях. На этом этапе ваше приложение может получать записи с изменениями. Вы можете указать токен изменения (CKServerChangeToken
), чтобы ограничить результаты запроса только теми записями, которые изменились с момента последней загрузки. У каждого устройства есть собственная подписка и токен, поэтому оно будет загружать только те данные и записывать необходимые изменения. Таким образом, CloudKit является источником истины , и все изменения - независимо от того, где они происходят - отражаются на других устройствах.
Вам не нужно ждать появления уведомления чтобы запросить изменения. CKFetchRecordZoneChangesOperation
всегда будет предоставлять новый токен изменения по завершении выполнения. Таким образом, получение изменений - это один и тот же процесс, независимо от того, как он запускается; с помощью уведомления или другого механизма, такого как изменение подключения, или вручную.
Вы можете создать подписку как для «publi c», так и для «частных» баз данных, чтобы гарантировать возможность отслеживания изменений для обеих.
CloudKit и схемы основных данных
Существует важное различие в том, как ваша модель будет структурирована между Core Data и CloudKit, и это проявляется в форме отношений.
Core Data рекомендует, чтобы все отношения были двунаправленными. Например: A Recipe
будет иметь отношение к своим Ingredient
s (один ко многим), И Ingredient
будет иметь отношение к его Recipe
(один к одному).
In CloudKit, рекомендуются только однонаправленные отношения с использованием CKReference
. Таким образом, для данного примера Recipe
не будет иметь прямой ссылки на ингредиенты, но Ingredient
будет иметь ссылку на связь с Recipe
, который его использует.
Как часть взаимодействия между Core Data и CloudKit, вам понадобится уникальный идентификатор, который можно запрашивать в обеих средах. Обычный способ добиться этого - использовать UUID
. CKRecord.ID
состоит из «recordName» (String) и «zoneID» (CKRecordZone.ID
). Использование UUID.uuidString
в качестве 'recordName' создаст уникальные записи в CloudKit, но также даст вам последовательную ссылку на сущности в Core Data.
Core Data
Как вы указали, автономный доступ к данным имеет решающее значение для удобства использования вашего приложения. Core Data - отличный вариант здесь. Даже если у вас есть возможность отображать результаты непосредственно из CKQuery
, сохранение этих данных имеет некоторые преимущества. Я рассматриваю локальное хранилище Core Data как интерфейс для всех данных в моем приложении. Это означает, что для моих пользовательских данных существует единый интерфейс.
Любое изменение, которое вносится в локальные данные, также отправляется в CloudKit, а любая запись, поступающая из CloudKit, добавляется или изменяется в локальных Core Data store.
Использование Core Data таким образом позволяет вам воспользоваться такими инструментами, как NSFetchedResultsController
, которые можно использовать для автоматического отражения изменений, внесенных в набор сущностей.
Кроме того, вы могут подключаться к Notification
NSManagedObjectContextDidSave
, помогают поддерживать пользовательский интерфейс ваших приложений в актуальном состоянии, когда изменения объединяются из взаимодействий CloudKit.
Помните, что попытка выполнения сложных задач с использованием NSPersistentContainer.viewContext
может привести к проблемы с производительностью, поэтому вы захотите ознакомиться с DispatchQueue
s.
Operations
Взаимодействие с CloudKit основано на операциях. Запросы и записи определены как подклассы Operation
. Каждая задача определяется и затем добавляется в очередь для обработки. Эти операции выполняются асинхронно. Я считаю полезным распространить этот стиль программирования на другие области вашего приложения.
Например: когда я создаю новый Recipe
, это Operation
против Core Data, а затем у меня Operation
для создания этой записи в CloudKit. Вторая операция зависит от первой и отменяется, если первая не удалась.
Становится немного легче думать о координации между Core Data и CloudKit как о серии задач, которые необходимо выполнить. . Уведомление об изменении доставляется в ваше приложение> Получить изменения (используя токен изменения)> Добавить / обновить эти записи в Core Data> Обновить пользовательский интерфейс (автоматически / вручную). Каждый из них является звеном в цепочке и зависит от последнего, которое должно быть завершено перед тем, как двигаться дальше. помочь с этим процессом.
В целом Core Data и CloudKit хорошо интегрируются друг с другом и обычно используются для того типа сценария, который вы пытаетесь реализовать. В зависимости от сложности или степени разработки, на которой вы находитесь, NSPersistentCloudKitContainer может быть хорошей отправной точкой. Но как только вы выйдете за рамки его возможностей, вам захочется узнать о проблемах и функциях, указанных выше.