Я нахожусь в процессе мозгового штурма решения облачной синхронизации для приложения 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» (имя не определено) будет содержать отдельные папки для каждого приложения, использующего инфраструктуру
- Каждая папка приложения содержит папку устройств и сущностей папка
- Папка devices будет содержать папку для каждого устройства, зарегистрированного в учетной записи. Папка устройства будет названа в соответствии с идентификатором устройства, полученным с использованием чего-то вроде
[[UIDevice currentDevice] uniqueIdentifier]
(в iOS) или серийного номера (в Mac OS).
- Каждая папка устройства содержит два файла: deviceinfo и changeset . deviceinfo содержит информацию об устройстве (например, версию ОС, дату последней синхронизации, модель и т. Д.), А файл changeset содержит информацию об объектах, которые изменились с момента последней синхронизации устройства. Оба файла будут просто простыми NSDictionaries, заархивированными в файлы с использованием
NSKeyedArchiver
.
- У каждого объекта Core Data есть подпапка в папке entity
- В каждой папке сущностей каждый объект, принадлежащий этой сущности, будет иметь отдельный файл. Этот файл будет содержать словарь JSON с парами ключ-значение.
Синхронная синхронизация
Это одна из областей, где я почти совершенно не в курсе. Как бы я обработал 2 устройства, подключающихся и синхронизирующихся с облаком одновременно? Похоже, существует высокий риск нарушения синхронизации или даже повреждения данных.
Обработка миграций
Еще раз, еще одна невежественная область здесь. Как бы я справился с миграциями модели управляемых объектов Core Data? Здесь проще всего просто очистить хранилище облачных данных и загрузить новую копию данных с устройства, которое подверглось процесс миграции, но это кажется несколько рискованным, и, возможно, есть лучший способ.
Клиентская сторона
Преобразование NSManagedObjects в JSON
Преобразование атрибутов в JSON не очень сложная задача (для этого существует множество кода, плавающего по сети).Отношения являются ключевой проблемой здесь.В этом сообщении stackoverflow Маркус Зарра публикует код, в котором сами объекты отношений добавляются в словарь JSON.Однако он упоминает, что это может вызвать бесконечный цикл в зависимости от структуры модели, и я не уверен, будет ли это работать с моим методом, потому что я сохраняю каждый объект как отдельный файл.
Iпытался найти способ получить идентификатор в виде строки для NSManagedObject
.Тогда я мог бы сохранить отношения в JSON как массив идентификаторов.Самым близким, что я нашел, был [[managedObject objectID] URIRepresentation]
, но на самом деле это не идентификатор объекта, это скорее место для объекта в постоянном хранилище, и я не знаю, достаточно ли его конкретно для использования в качестве ссылкидля объекта.
Полагаю, я мог бы сгенерировать строку UUID для каждого объекта и сохранить ее как атрибут, но я открыт для предложений.
Синхронизация изменений в облаке
Первое (и все еще лучшее) решение, которое пришло мне в голову, это прослушать NSManagedObjectContextObjectsDidChangeNotification
, чтобы получить список измененных объектов, а затем обновить / удалить / вставить эти объекты воблачное хранилище данных.После сохранения изменений мне нужно обновить файл changeset для каждого другого зарегистрированного устройства, чтобы отразить вновь измененные объекты.
Одна проблема, которая возникает здесь, как бы я справился с неудачной или прерванной синхронизацией? .У меня есть одна идея: сначала перенести изменения во временный каталог в облаке, а затем, если он был подтвержден как успешный, объединить его с основными данными в облаке, чтобы прерывание в середине синхронизации не повредилоданные.Затем я хотел бы сохранить записи объектов, которые должны быть обновлены в облаке, в файл plist или что-то еще для последующей отправки при следующем подключении приложения к Интернету.
Получение измененных объектов
Это довольно просто, устройство загружает свой файл changeset , выясняет, какие объекты необходимо обновить / вставить / удалить, и затем действует соответствующим образом.
И это подводит итог моим мыслям о логике, которую будет использовать эта система :-) Любое понимание, предложения, ответы на проблемы и т. Д. очень приветствуется.
ОБНОВЛЕНИЕ
После долгих раздумий и прочтения предложений TechZens я предложил несколько модификаций своей концепции.
Самое большое изменение, которое я придумал, состоит в том, чтобы каждое устройство имело отдельный хранилище данных в облаке.По сути, каждый раз, когда контекст управляемого объекта сохраняет (спасибо TechZen), он загружает изменения в хранилище данных этого устройства.После того, как эти изменения будут обновлены, он создаст файл «changeset» с деталями изменений и сохранит его в папках наборов изменений ДРУГИХ устройств, которые используют приложение.Когда другие устройства подключаются к синхронизации, они проходят через папку наборов изменений и применяют каждый набор изменений к локальному хранилищу данных, а затем обновляют свои соответствующие хранилища данных в облаке.
Теперь, если новое устройствозарегистрированный под учетной записью, он найдет новейшую копию данных со всех устройств и загрузит ее для использования в качестве локального хранилища. Это решает проблему одновременной синхронизации и уменьшает шансы на повреждение данных, поскольку отсутствует «центральное» хранилище данных, каждое устройство касается только своих данных и просто обновляет изменения, а не каждое устройство обращается и изменяет одни и те же данные.в то же время.
Есть несколько очевидных конфликтных ситуаций, в основном связанных с удалением объектов.Если загружается набор изменений, указывающий приложению удалить объект, который в данный момент редактируется, и т. Д., Должны быть способы с этим справиться.