Я нахожусь в центре мозгового штурма решения для облачной синхронизации для приложения Core Data, которое я сейчас разрабатываю. Я планирую открыть исходный код для этого, как только это будет сделано, для тех, кто использует их приложения с основными данными, поэтому вклад сообщества в то, как эта система должна работать, очень ценится:-) Вот что я думаю:
Сторона сервера
Поставщик средств хранения
Как и во всех облачных системах синхронизации, хранилище является основной частью головоломки. Есть много способов справиться с этим. Я могу настроить свой собственный сервер для хранения или использовать службу, такую как Amazon S3, но поскольку я начинаю с капитала в 0 долларов, на данный момент платное решение для хранения данных не является жизнеспособным вариантом. После некоторого раздумья я решил согласиться с Dropbox (уже зарекомендовавший себя приложение для облачной синхронизации и хранилище). Преимущества использования Dropbox:
- Это бесплатно (для ограниченного пространства)
- Помимо службы хранения данных, она также обрабатывает синхронизацию с облаками
- Недавно они выпустили SDK Objective-C, который упрощает взаимодействие с ним в приложениях 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 содержит информацию об устройстве (например, версия ОС, последняя дата синхронизации, модель и т.д.), а файл changeet содержит информацию об объектах, которые были изменены с момента последнего синхронизированного устройства, Оба файла будут просто простыми NSDictionaries, заархивированными в файлы с помощью
NSKeyedArchiver
. - Каждый объект Data Data имеет подпапку в папке сущности
- Под каждой папкой сущности каждый объект, принадлежащий этому объекту, будет иметь отдельный файл. Этот файл будет содержать словарь JSON с парами ключ-значение.
Синхронная синхронизация
Это одна из тех областей, где я почти совершенно не знаю. Как я могу обрабатывать 2 устройства, которые одновременно соединяются и синхронизируются с облаком?. Кажется, существует высокий риск того, что здесь не получается синхронизация или даже повреждение данных.
Обработка миграции
Еще раз, другая невежественная область здесь. Как я могу обрабатывать миграции модели объектов, управляемых базовыми данными?. Проще всего сделать здесь, похоже, просто очистить хранилище данных облачных данных и загрузить новую копию данных с устройства, которое прошли процесс миграции, но это кажется несколько рискованным, и может быть лучший способ.
Клиентская сторона
Преобразование NSManagedObjects в JSON
Преобразование атрибутов в JSON - это не очень сложная задача (это много кода для нее, плавающего по сети). Здесь важны отношения. В этом postoverflow post, Marcus Zarra отправляет код, в который сами объекты отношений добавляются в словарь JSON. Однако он упоминает, что это может вызвать бесконечный цикл в зависимости от структуры модели, и я не уверен, что это будет работать с моим методом, потому что я храню каждый объект как отдельный файл.
Я пытаюсь найти способ получить идентификатор в виде строки для NSManagedObject
. Тогда я мог бы сохранить отношения в JSON как массив идентификаторов. Самое близкое, что я обнаружил, это [[managedObject objectID] URIRepresentation]
, но это не действительно идентификатор для объекта, его больше места для объекта в постоянном хранилище, и я не знаю, достаточно ли его достаточно для использования в качестве ссылки для объекта.
Я предполагаю, что я могу создать строку UUID для каждого объекта и сохранить ее как атрибут, но я открыт для предложений.
Синхронизация изменений в облаке
Первое (и еще лучшее) решение, появившееся в моей голове, состояло в том, чтобы прослушать NSManagedObjectContextObjectsDidChangeNotification
, чтобы получить список измененных объектов, а затем обновить/удалить/вставить эти объекты в хранилище облачных данных. После того, как изменения сохранены, мне нужно будет обновить файл changeet для каждого другого зарегистрированного устройства, чтобы отразить вновь измененные объекты.
Одна из проблем, которая возникает здесь, - , как я могу обрабатывать неудачную или прерванную синхронизацию?. Одна из моих идей заключается в том, чтобы сначала вносить изменения во временный каталог в облаке, а затем, как только это было подтверждено как успешное, объединить его с основными данными в облаке, чтобы прерывание в середине синхронизации не испортилось данные. Затем я бы сохранил записи объектов, которые необходимо обновить в облаке, в файл plist или что-то еще, чтобы быть нажатым в следующий раз, когда приложение подключено к Интернету.
Извлечение измененных объектов
Это довольно просто, устройство загружает файл changeet, определяет, какие объекты нужно обновлять/вставлять/удалять, а затем действует соответственно.
И это подводит итог моим мыслям о логике, которую эта система будет использовать:-) Большое понимание, предложения, ответы на проблемы и т.д. приветствуется.
UPDATE
После долгих размышлений и чтения предложений TechZens я придумал некоторые изменения в моей концепции.
Самое большое изменение, которое я придумал, - заставить каждое устройство иметь отдельное хранилище данных в облаке. В принципе, каждый раз, когда контекст управляемого объекта сохраняет (спасибо TechZen), он будет загружать изменения в это хранилище данных устройства. После того, как эти изменения будут обновлены, он создаст файл изменений с изменениями и сохранит его в папках наборов изменений других устройств, которые используют приложение. Когда другие устройства подключаются к синхронизации, они будут проходить через папку набора изменений и применять каждый набор изменений в локальном хранилище данных, а затем обновлять соответствующие хранилища данных в облаке.
Теперь, если новое устройство зарегистрировано в учетной записи, оно найдет самую последнюю копию данных из всех устройств и загрузит ее для использования в качестве своего локального хранилища. Это решает проблему синхронной синхронизации и снижает вероятность повреждения данных, поскольку нет "центрального" хранилища данных, каждое устройство касается только своих данных и просто обновляет изменения, а не все устройства, которые обращаются к ним и изменяют их данные в то же время.
Есть некоторые очевидные конфликтные ситуации, с которыми приходится иметь дело, главным образом, в отношении удаления объектов. Если набор изменений загружается, инструктируя приложение удалить объект, который в настоящее время редактируется, и т.д., Должны быть способы борьбы с этим.