Синхронизация облачных данных Core Data – нужна помощь с логикой

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

Серверная сторона


Поставщик хранилища

Как и во всех облачных системах синхронизации, хранилище является основной частью головоломки. Есть много способов справиться с этим. Я могу настроить свой собственный сервер для хранения или использовать службу, такую ​​как Amazon S3, но поскольку я начинаю с капитала в 0 долларов, на данный момент платное решение для хранения данных не является жизнеспособным вариантом. Подумав, я решил согласиться с Dropbox (уже хорошо зарекомендовавшим себя приложением облачной синхронизации и поставщиком хранилища). Преимущества использования Dropbox:

  • Это бесплатно (для ограниченного пространства)
  • Помимо службы хранения данных, он также обрабатывает облачную синхронизацию
  • Недавно они выпустили Objective-C SDK, который упрощает взаимодействие с ним в приложениях Mac и iPhone

В случае, если в будущем я захочу переключиться на другого поставщика хранилища, я намерен добавить «сервисы» к этой инфраструктуре облачной синхронизации, в основном позволяя любому создавать класс обслуживания для взаимодействия с их выбором поставщика хранилища, который тогда может просто быть подключен к инфраструктуре.

Структура хранилища

Это очень сложная часть, чтобы понять, так что мне нужно столько информации, сколько я могу здесь. Я думал о такой структуре:

CloudSyncFramework ======> [app name] ==========> devices =============> (device id) ================> deviceinfo ================> changeset ==========> entities =============> (entity name) ================> (object id) 

Краткое объяснение этой структуры:

  • Основная папка «CloudSyncFramework» (имя не определено) будет содержать отдельные папки для каждого приложения, которое использует структуру
  • Каждая папка приложения содержит папку устройств и папку сущностей
  • Папка устройств будет содержать папку для каждого устройства, зарегистрированного в учетной записи. Папка устройства будет называться в соответствии с идентификатором устройства, полученным с использованием, например, [[UIDevice currentDevice] uniqueIdentifier] (на iOS) или серийного номера (в Mac OS).
  • Каждая папка устройства содержит два файла: deviceinfo и changeet . deviceinfo содержит информацию об устройстве (например, версия ОС, последняя дата синхронизации, модель и т. д.), а файл набора изменений содержит информацию об объектах, которые были изменены с момента последней синхронизации устройства. Оба файла будут просто простыми NSDictionaries, заархивированными в файлы с помощью NSKeyedArchiver .
  • Каждый объект Core Data имеет подпапку под папкой сущностей
  • Под каждой папкой сущности каждый объект, принадлежащий этому объекту, будет иметь отдельный файл. Этот файл будет содержать словарь JSON с парами ключ-значение.

Одновременная синхронизация

Это одна из областей, где я почти совершенно не знаю. Как я могу обрабатывать 2 устройства, которые одновременно соединяются и синхронизируются с облаком? Кажется, существует высокий риск того, что здесь не получается синхронизация или даже повреждение данных.

Обработка миграции

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

Сторона клиента


Преобразование NSManagedObjects в JSON

Преобразование атрибутов в JSON – это не очень сложная задача (это много кода для плавания в Интернете). Здесь важны отношения. В этой записи stackoverflow Marcus Zarra отправляет код, в который сами объекты отношений добавляются в словарь JSON. Однако он упоминает, что это может вызвать бесконечный цикл в зависимости от структуры модели, и я не уверен, будет ли это работать с моим методом, потому что я храню каждый объект в виде отдельного файла.

Я пытался найти способ получить идентификатор в виде строки для NSManagedObject . Тогда я мог бы сохранить отношения в JSON как массив идентификаторов. Самое близкое, что я обнаружил, это [[managedObject objectID] URIRepresentation] , но на самом деле это не ID для объекта, его больше места для объекта в постоянном хранилище, и я не знаю, достаточно ли его достаточно для того, чтобы использовать в качестве ссылки для объекта.

Я предполагаю, что я могу создать строку UUID для каждого объекта и сохранить ее как атрибут, но я открыт для предложений.

Синхронизация изменений в облаке

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

Одна из проблем, которая возникает здесь, заключается в том , как мне обрабатывать неудачную или прерванную синхронизацию? , Одна из моих идей заключается в том, чтобы сначала вносить изменения во временный каталог в облаке, а затем, как только это было подтверждено как успешное, объединить его с основными данными в облаке, чтобы прерывание в середине синхронизации не испортилось данные. Затем я сохранил записи объектов, которые необходимо обновить в облаке, в файл plist или что-то еще, чтобы быть нажатым в следующий раз, когда приложение подключено к Интернету.

Получение измененных объектов

Это довольно просто, устройство загружает файл своих изменений , выясняет, какие объекты нужно обновлять / вставлять / удалять, а затем действует соответственно.

И это суммирует мои мысли о логике, которую эта система будет использовать 🙂 Большое понимание, предложения, ответы на проблемы и т. Д.

ОБНОВИТЬ

После долгих размышлений и чтения предложений TechZens я придумал некоторые изменения в моей концепции.

Самое большое изменение, которое я придумал, – заставить каждое устройство иметь отдельное хранилище данных в облаке. В принципе, каждый раз, когда сохраняется контекст управляемого объекта (благодаря TechZen), он будет загружать изменения в хранилище данных этого устройства. После того, как эти изменения будут обновлены, он создаст файл изменений с изменениями и сохранит его в папках наборов изменений других устройств, которые используют приложение. Когда другие устройства подключаются к синхронизации, они будут проходить через папку набора изменений и применять каждый набор изменений в локальном хранилище данных, а затем обновлять соответствующие хранилища данных в облаке.

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

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

Вы хотите посмотреть на этот пессимистический подход на облачную синхронизацию: почему Cloud Sync никогда не будет работать. Он охватывает множество проблем, с которыми вы боретесь. Многие из них в значительной степени трудноразрешимы.

Синхронизировать информационный период очень, очень и очень сложно. Добавление в разные устройства, различные операционные системы, различные структуры данных и т. Д. Часто ускоряют сложность. Люди работают над вариантами этой проблемы с 70-х годов, и вещи действительно не улучшились.

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

Как я могу обрабатывать 2 устройства, которые одновременно соединяются и синхронизируются с облаком?

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

Простейшей системой является установка либо канонического устройства, либо иерархии устройства, так что система всегда знает, какой вход выбрать. Это, однако, разрушает гибкость.

Как мне обрабатывать миграции модели объектов, управляемых базовыми данными?

Перенос модели Core Data в значительной степени не имеет отношения к серверу. Это то, что Core Data управляет внутренне для себя. Модель миграции обновляет модель, то есть граф объекта, а не фактические данные.

Преобразование NSManagedObjects в JSON

Моделирование отношений сложно, особенно с инструментами, которые не поддерживают его так же легко, как Core Data. Однако URI идентификатора управляемого управляемого объекта должен служить UUID, который прибивает объект до определенного места в определенном хранилище на определенном устройстве. Это технически не гарантировано универсально уникально, но оно достаточно близко для всех практических целей.

Синхронизация изменений в облаке

Я думаю, что вы запутываете детали реализации Core Data с самим облаком. Если вы используете NSManagedObjectContextObjectsDidChangeNotification вы будете вызывать сетевой трафик каждый раз, когда наблюдаемый контекст изменяется независимо от того, сохраняются ли эти изменения или нет. В зависимости от приложения, это может привести к подключению тысячи раз в несколько минут. Вместо этого вы хотите синхронизировать только при сохранении контекста.

Одна из проблем, которая возникает здесь, заключается в том, как мне обрабатывать неудачную или прерванную синхронизацию?

Вы не фиксируете изменения до завершения синхронизации. Это большая проблема и приводит к повреждению данных. Опять же, вы можете иметь гибкость, сложность, хрупкость или гибкость, простоту и надежность.

Извлечение измененных объектов: это довольно просто, устройство загружает файл своего набора изменений, выясняет, какие объекты нужно обновлять / вставлять / удалять, а затем действует соответственно

Это просто, если у вас есть негибкая структура данных. Описание изменений в гибкой структуре данных – это кошмар.

Не уверен, помог ли я кому-нибудь. Ни одна из проблем не имеет изящных решений. Большинство дизайнеров в конечном итоге с жесткостью и / или медленным, грубой силы итеративного слияния.

Взгляните на RestKit серьезно .

Это проект с открытым исходным кодом, целью которого является интеграция приложений iOS с облачными данными, включая, но не ограничиваясь, сценарий, в котором для данных на клиенте имеется модель данных ядра.

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

RestKit отнюдь не является зрелым продуктом, но имеет неплохую основу и немало вещей, которые могут использовать помощь других участников. Особенно, если ваша цель – создать решение с открытым исходным кодом, было бы здорово внести свой вклад и улучшить что-то подобное, вместо того чтобы повторно изобретать новое решение. Если, конечно, вы не видите серьезных различий между тем, что вы имеете в виду, и другими существующими решениями 🙂

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

Ниже приведен краткий список основных параметров синхронизации Core Data:

  1. Собственная синхронизация Core Data / iCloud от Apple. (Было скалистое начало. Кажется, теперь лучше.)
  2. TICDS
  3. Wasabi Sync , платная услуга.
  4. Симпериум (кажется, заброшен.)
  5. ParcelKit с API-интерфейсом Dropbox Datastore
  6. Ансамбли , самые последние. (Раскрытие информации: Я являюсь основателем проекта)

Это похоже на то, что Apple ответила на мой вопрос для меня с анонсом SDK iCloud , который поставляется с интеграцией Core Data. Выиграть!

Interesting Posts

Как я могу получить текущий месяц как String в swift:

Отключить перетаскивание в верхней части UIWebView / UIScrollView (жест «Pull to refresh»)

Зачем мне писать инициализатор для структуры в Swift, чтобы использовать его в модульных тестах?

Как получить доступ к нескольким контроллерам View из App Delegate и / или другим контроллерам View?

Полноэкранный UIScrollView не работает правильно

Проблема с плагином для информации о сети PhoneGap на iOS

нарисуйте только верхнюю, правую и нижнюю границы вокруг uilabel

Вызов viewWillAppear в UITableviewController

С iOS Photos Framework, как я могу отобразить все доступные PHAssetCollections?

Приглашение друзей Facebook через приложение iPhone

Не удалось создать тестовую версию Swift

Синтаксис UITableView для вызова cellForRowAtIndexPath: для всех ячеек

Получите NSData прямо из AFNetworking, вместо того, чтобы позволить ему конвертировать в UIImage

Как выбрать соответствие экспорта в моем приложении?

Xcode – Как переключить просмотр в раскадровке

Давайте будем гением компьютера.