Я работал над способом синхронизации основных данных, хранящихся в приложении iPhone, между несколькими устройствами, такими как iPad или Mac. Существует не так много (если вообще имеется) синхронизирующих сред для использования с Core Data на iOS. Тем не менее, я думал о следующей концепции:
- Внесено изменение в локальное базовое хранилище данных, и оно сохранено. (a) Если устройство подключено к сети, оно пытается отправить набор изменений на сервер, включая идентификатор устройства, отправившего набор изменений. (b) Если набор изменений не достигает сервера или если устройство не подключено к Интернету, приложение добавит набор изменений в очередь для отправки, когда он появится в сети.
- Сервер, находящийся в облаке, объединяет конкретные наборы изменений, которые он получает, со своей основной базой данных.
- После объединения набора изменений (или очереди наборов изменений) на облачном сервере сервер отправляет все эти наборы изменений на другие устройства, зарегистрированные на сервере, с использованием какой-либо системы опроса. (Я думал использовать сервисы Push от Apple, но, судя по комментариям, эта система не работает).
Есть ли что-нибудь необычное, о чем мне нужно подумать? Я посмотрел на каркасы REST, такие как ObjectiveResource , Core Resource и RestfulCoreData . Конечно, все они работают с Ruby on Rails, с которым я не связан, но это место для начала. Основные требования к моему решению:
- Любые изменения следует отправлять в фоновом режиме, не останавливая основной поток.
- Следует использовать как можно меньшую пропускную способность.
Я подумал о ряде проблем:
- Убедитесь, что идентификаторы объектов для разных хранилищ данных на разных устройствах прикреплены на сервере. То есть у меня будет таблица идентификаторов объектов и идентификаторов устройств, которые связаны через ссылку на объект, хранящийся в базе данных. У меня будет запись (DatabaseId [уникальный для этой таблицы], ObjectId [уникальный для элемента во всей базе данных], Datafield1, Datafield2), поле ObjectId будет ссылаться на другую таблицу, AllObjects: (ObjectId, DeviceId, DeviceObjectId). Затем, когда устройство отправляет набор изменений, оно передает идентификатор устройства и идентификатор объекта из основного объекта данных в локальном хранилище данных. Затем мой облачный сервер проверит соответствие objectId и идентификатора устройства в таблице AllObjects и найдет запись для изменения в исходной таблице.
- Все изменения должны иметь временные метки, чтобы их можно было объединить.
- Устройству придется опрашивать сервер, не расходуя слишком много батареи.
- Локальные устройства также должны будут обновлять все, что хранится в памяти, если / когда изменения получены от сервера.
Есть ли что-то еще, что мне здесь не хватает? На какие рамки мне следует обратить внимание, чтобы сделать это возможным?
Ответы:
Я предлагаю внимательно прочитать и реализовать стратегию синхронизации, обсуждаемую Дэном Гровером на конференции iPhone 2009, которая доступна здесь в виде документа в формате PDF.
Это жизнеспособное решение, и его не так сложно реализовать (Дэн реализовал это в нескольких своих приложениях), перекрывая решение, описанное Крисом. Подробное теоретическое обсуждение синхронизации см. В статье Русса Кокса (MIT) и Уильяма Джозефсона (Принстон):
Синхронизация файлов с векторными временными парами
который одинаково хорошо применим к основным данным с некоторыми очевидными изменениями. Это обеспечивает в целом гораздо более надежную и надежную стратегию синхронизации, но требует больше усилий для правильной реализации.
РЕДАКТИРОВАТЬ:
Похоже, что файл PDF Гровера больше не доступен (неработающая ссылка, март 2015 г.). ОБНОВЛЕНИЕ: ссылка доступна через Way Back Machine здесь
Фреймворк Objective-C под названием ZSync, разработанный Маркусом Заррой, устарел, учитывая, что, похоже, iCloud наконец-то поддерживает правильную синхронизацию данных ядра.
источник
Я сделал что-то похожее на то, что вы пытаетесь сделать. Позвольте мне рассказать вам, что я узнал и как я это сделал.
Я предполагаю, что между вашим объектом Core Data и моделью (или схемой БД) на сервере есть взаимно-однозначное отношение. Вы просто хотите синхронизировать содержимое сервера с клиентами, но клиенты также могут изменять и добавлять данные. Если я правильно понял, тогда продолжайте читать.
Я добавил четыре поля, чтобы помочь с синхронизацией:
На клиенте добавьте код, чтобы задать для sync_status значение 1 для объекта модели всякий раз, когда что-то изменяется и его необходимо синхронизировать с сервером. Новые объекты модели должны генерировать GUID.
Синхронизация - это один запрос. Запрос содержит:
Сервер получает запрос и делает это:
Приложение получает ответ и делает это:
Надеюсь, это поможет. Я использовал слово запись и модель взаимозаменяемо, но я думаю, вы поняли идею. Удачи.
источник
MAX(last_modified)
, но это было бы излишним, так какMAX(last_modified)
достаточно. Уsync_status
него другая роль. Как я писал ранее,MAX(last_modified)
определяет, что должно быть синхронизировано с сервером, иsync_status
определяет, что должно быть синхронизировано с сервером.Если вы все еще ищете способ пойти, посмотрите на мобильный телефон Couchbase. Это в основном делает все, что вы хотите. ( http://www.couchbase.com/nosql-databases/couchbase-mobile )
источник
Подобно @Cris, я реализовал класс для синхронизации между клиентом и сервером и до сих пор решил все известные проблемы (отправка / получение данных на сервер / с сервера, слияние конфликтов на основе временных меток, удаление дублированных записей в ненадежных сетевых условиях, синхронизация вложенных данных и файлы и т.д ..)
Вы просто сообщаете классу, какая сущность и какие столбцы должны синхронизироваться и где находится ваш сервер.
Вы можете найти источник, рабочий пример и другие инструкции здесь: github.com/knagode/M3Synchronization .
источник
Уведомить пользователя обновить данные с помощью push-уведомления. Используйте фоновый поток в приложении, чтобы проверить локальные данные и данные на облачном сервере, в то время как изменение происходит на сервере, измените локальные данные, и наоборот.
Поэтому я думаю, что самая сложная часть - это оценить данные, в которых сторона недействительна.
Надеюсь, это поможет тебе
источник
Я только что опубликовал первую версию моего нового API синхронизации Core Data Cloud, известного как SynCloud. SynCloud имеет много различий с iCloud, потому что он позволяет многопользовательский интерфейс синхронизации. Он также отличается от других синхронизирующих API-интерфейсов, поскольку позволяет использовать многотабличные реляционные данные.
Пожалуйста, узнайте больше на http://www.syncloudapi.com
Сборка с iOS 6 SDK, он очень актуален по состоянию на 27.09.2012.
источник
Я думаю, что хорошим решением проблемы GUID является «система распределенных идентификаторов». Я не уверен, каков правильный термин, но я думаю, что именно так назывались документы MS SQL Server (SQL использует / использовал этот метод для распределенных / синхронизированных баз данных). Это довольно просто:
Сервер назначает все идентификаторы. Каждый раз, когда выполняется синхронизация, первое, что проверяется: «Сколько идентификаторов у меня осталось на этом клиенте?» Если клиенту не хватает, он запрашивает у сервера новый блок идентификаторов. Затем клиент использует идентификаторы в этом диапазоне для новых записей. Это отлично подходит для большинства задач, если вы можете назначить блок достаточно большой, чтобы он «никогда» не заканчивался до следующей синхронизации, но не настолько большой, чтобы сервер со временем заканчивал работу. Если клиент когда-либо закончится, обработка может быть довольно простой, просто скажите пользователю «извините, что вы не можете добавить больше элементов, пока вы не синхронизируете» ... если они добавляют столько элементов, не должны ли они синхронизироваться, чтобы избежать устаревших данных проблемы в любом случае?
Я думаю, что это лучше, чем использование случайных идентификаторов GUID, поскольку случайные идентификаторы GUID не являются безопасными на 100% и обычно должны быть намного длиннее стандартного идентификатора (128 бит по сравнению с 32 битами). У вас обычно есть индексы по идентификатору и вы часто храните их в памяти, поэтому важно, чтобы они были небольшими.
На самом деле не хотел публиковать в качестве ответа, но я не знаю, что кто-то будет видеть в качестве комментария, и я думаю, что это важно для этой темы и не включены в другие ответы.
источник
Сначала вы должны переосмыслить, сколько данных, таблиц и отношений у вас будет. В моем решении я реализовал синхронизацию через файлы Dropbox. Я наблюдаю за изменениями в основном MOC и сохраняю эти данные в файлы (каждая строка сохраняется как gzipped json). Если работает интернет-соединение, я проверяю, есть ли какие-либо изменения в Dropbox (Dropbox дает мне дельта-изменения), загружаю их и объединяю (последние победы), и, наконец, помещаю измененные файлы. Перед синхронизацией я помещаю файл блокировки в Dropbox, чтобы другие клиенты не синхронизировали неполные данные. При загрузке изменений безопасно, что загружаются только частичные данные (например, потеря соединения с интернетом). Когда загрузка завершена (полностью или частично), она начинает загружать файлы в Core Data. Когда возникают неразрешенные отношения (не все файлы загружаются), он прекращает загрузку файлов и пытается завершить загрузку позже. Отношения хранятся только как GUID, поэтому я могу легко проверить, какие файлы загружать, чтобы иметь полную целостность данных. Синхронизация начинается после внесения изменений в основные данные. Если изменений нет, то он проверяет наличие изменений в Dropbox каждые несколько минут и при запуске приложения. Дополнительно, когда изменения отправляются на сервер, я отправляю широковещательную рассылку другим устройствам, чтобы сообщить им об изменениях, чтобы они могли синхронизироваться быстрее. Каждый синхронизируемый объект имеет свойство GUID (guid также используется в качестве имени файла для файлов обмена). У меня также есть база данных Sync, где я сохраняю ревизию Dropbox каждого файла (я могу сравнить ее, когда дельта-сброс Dropbox сбрасывает его состояние) Файлы также содержат имя сущности, состояние (удалено / не удалено), guid (аналогично имени файла), ревизию базы данных (для обнаружения миграции данных или во избежание синхронизации с никогда не версиями приложения) и, конечно, данные (если строка не удалена). так что я могу легко проверить, какие файлы загружать, чтобы иметь полную целостность данных. Синхронизация начинается после внесения изменений в основные данные. Если изменений нет, то он проверяет наличие изменений в Dropbox каждые несколько минут и при запуске приложения. Дополнительно, когда изменения отправляются на сервер, я отправляю широковещательную рассылку другим устройствам, чтобы сообщить им об изменениях, чтобы они могли синхронизироваться быстрее. Каждый синхронизируемый объект имеет свойство GUID (guid также используется в качестве имени файла для файлов обмена). У меня также есть база данных Sync, где я сохраняю ревизию Dropbox каждого файла (я могу сравнить ее, когда дельта-сброс Dropbox сбрасывает его состояние) Файлы также содержат имя сущности, состояние (удалено / не удалено), guid (аналогично имени файла), ревизию базы данных (для обнаружения миграции данных или во избежание синхронизации с никогда не версиями приложения) и, конечно, данные (если строка не удалена). так что я могу легко проверить, какие файлы загружать, чтобы иметь полную целостность данных. Синхронизация начинается после внесения изменений в основные данные. Если изменений нет, то он проверяет наличие изменений в Dropbox каждые несколько минут и при запуске приложения. Дополнительно, когда изменения отправляются на сервер, я отправляю широковещательную рассылку другим устройствам, чтобы сообщить им об изменениях, чтобы они могли синхронизироваться быстрее. Каждый синхронизируемый объект имеет свойство GUID (guid также используется в качестве имени файла для файлов обмена). У меня также есть база данных Sync, где я сохраняю ревизию Dropbox каждого файла (я могу сравнить ее, когда дельта-сброс Dropbox сбрасывает его состояние) Файлы также содержат имя сущности, состояние (удалено / не удалено), guid (аналогично имени файла), ревизию базы данных (для обнаружения миграции данных или во избежание синхронизации с никогда не версиями приложения) и, конечно, данные (если строка не удалена).
Это решение работает для тысяч файлов и около 30 объектов. Вместо Dropbox я мог бы использовать хранилище ключей / значений в качестве веб-службы REST, что я хочу сделать позже, но у меня нет на это времени :) На данный момент, на мой взгляд, мое решение более надежно, чем iCloud и, что очень важно, Я полностью контролирую, как это работает (в основном потому, что это мой собственный код).
Другое решение - сохранить изменения MOC как транзакции - с сервером будет обмениваться гораздо меньше файлов, но сложнее выполнить первоначальную загрузку в правильном порядке в пустые данные ядра. iCloud работает таким же образом, и другие решения для синхронизации имеют аналогичный подход, например, TICoreDataSync .
-- ОБНОВИТЬ
Через некоторое время я перешел на ансамбли - я рекомендую это решение, а не изобретать велосипед.
источник