iCloud + CoreData - как избежать дублирования предварительно заполненных данных? - PullRequest
15 голосов
/ 01 февраля 2012

У меня проблема с приложением для обувной коробки iCloud, и я надеюсь, что кто-нибудь мне поможет (я потратил много часов на борьбу с ним напрасно).

Приложение: - Простое приложение в стиле библиотеки, содержащее набор категорий (Cat1 .. CatN), каждая из которых содержит элементы (Item1 ... ItemM). Я использовал Apple iPhoneCoreDataRecipes для настройки стека iCloud CoreData.

С iCloud все работает почти идеально, за исключением того, что должно быть несколько предварительно заполненных пустых категорий, которые пользователь может начать использовать после первого запуска приложения (он также может быть отключен в это время). А вот и дьявол.

Вот что я делаю - как только мой persistentStoreCoordinator настроен, я отправляю уведомление

dispatch_async(dispatch_get_main_queue(), ^{
    [[NSNotificationCenter defaultCenter]
        postNotificationName: @"RefetchAllDatabaseData"
                      object: self
                    userInfo: nil];
    });

который получен моим MasterViewController. Когда уведомление получено, MasterViewController проверяет количество категорий в хранилище. Если количество доступных категорий равно 0 - вставляются предварительно заполненные категории.

К вашему сведению - я использую NSMergeByPropertyObjectTrumpMergePolicy для моего ManagedObjectContext

Проблема: Это хорошо работает для 1-го устройства. Но для 2-го устройства категории по умолчанию от iCloud часто получены позже, чем был установлен persistentStoreCoordinator (и категории по умолчанию вставлены 2-м устройством). В конце у меня есть 2 набора категорий с одинаковыми именами на обоих устройствах.

Есть идеи, как это можно решить?

Пробные решения: Я попробовал 2 стратегии, чтобы решить эту проблему. Оба начинаются одинаково. После того, как я позвоню

[moc mergeChangesFromContextDidSaveNotification: note];

я звоню

[self materializeKeysWithUserInfo: note.userInfo forContext: moc];

большое спасибо Хосе Инесу Канту Аррамбиде из https://devforums.apple.com/thread/126670?start=400&tstart=0 за его код ссылки - по сути

materializeKeysWithUserInfo:forContext:

получает managedObjectIds из note.userInfo и извлекает соответствующие объекты из ManagedObjectContext, помещая их в словарь.

Стратегия 1:

  • Все мои категории имеют метки времени создания.
  • При вставке из iCloud, получить пары категорий с одинаковыми именами, если таковые имеются
  • Выберите старые категории дубликатов
  • переместить свои предметы в более новые категории дубликатов
  • удалить старые повторяющиеся категории

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

1) предметы с 1-го устройства теряются на 2-м устройстве - когда они попадают на 2-е устройство, их родительская категория отсутствует и их поле категории равно нулю, поэтому я не знаю, куда их поместить.

2) через некоторое время элементы, потерянные на втором устройстве, также теряются на первом из-за конфликтов.

3) некоторые предметы со 2-го устройства также теряются из-за конфликтов.

Я пытался предпочесть более старые категории новым, но это не дало никакого эффекта

Стратегия 2:

  • Все мои категории имеют метки времени создания.
  • Все категории имеют устаревшее логическое поле, установленное на NO при создании
  • При вставке из iCloud, получить пары категорий с одинаковыми именами, если они есть
  • Выберите старые категории дубликатов
  • переместить свои предметы в новые двойные категории
  • пометьте старые категории с устарело = ДА

Эти стратегии почти всегда удаляют дубликаты на обоих устройствах еще до того, как они появляются в интерфейсе пользователя НО

Большинство (или все) предметов с обоих устройств теряются из-за множества конфликтов по категориям и предметам.

Некоторые заключительные мысли:

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

В моих тестах оба устройства работали одновременно.Я не могу игнорировать случай, когда счастливый пользователь, который только что купил свой 2-й iDevice, устанавливает мое приложение на 2-е устройство (при котором приложение запускается на 1-м устройстве) и теряет все свои элементы в считанные минуты.

Есть идеи, как решить эту ситуацию?Как вы думаете, iCloud + CoreData готов к работе?

Стратегия 3

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

iCloud не знает о данныхкоторый существует в базе данных до установки iCloud - мое 2-е устройство получает элементы, вставленные на 1-е устройство в предварительно заполненные категории, с категорией = ноль.

Элементы в дополнительных категориях (а также сами категории) вставленыв хранилище после настройки iCloud правильно синхронизировать.

1 Ответ

3 голосов
/ 03 февраля 2012

Стратегия 1 с некоторыми изменениями оказалась рабочим решением (хотя с некоторыми недостатками).

Легенда:

  • 1-е устройство - запущено в сети без содержимого в iCloud
  • 2-е устройство - запущено позже, чем первое и в автономном режиме. Затем он становится онлайн после добавления некоторых предметов

Итак, вот обновленная стратегия:

  • Все мои категории имеют создание отметки времени

  • Категории не могут быть переименованы (только добавлены или удалены - это крайне важно)

  • Все мои элементы имеют строковое поле categoryName, которое получает свое значение при создании элемента и обновляется при перемещении элемента в другую категорию - эта избыточная информация помогает достичь успеха;

При добавлении новых Категории :

  • При вставке из iCloud я получаю пары категорий с одинаковыми именами, если таковые имеются

  • Выберите более новые дубликаты категорий (у них, скорее всего, будет меньше элементов, чем у старых, поэтому у нас будет меньше танцев в iCloud)

  • Переместите свои предметы, если таковые имеются, в старше дублирующихся категорий

  • Удалить новее дублировать категории

При добавлении новых Элементов - если элемент принадлежит Удалено Категория:

  • CoreData пытается объединить его, и терпит неудачу , так как родительской категории больше нет (множество ошибок в консоли). Он обещает вставить его позже.

  • Через некоторое время объединяется и вставляет элемент в хранилище, но с NIL , категория

  • Здесь мы выбираем наш элемент, выясняем его родительскую категорию из categoryName и относим его к правильной категории

VOILA! - без дубликатов и все счастливы

Пара заметок:

  1. Я получаю танец предметов, принадлежащих второму устройству (те, которые придут с нулевой категорией к первому устройству) на обоих устройствах. Через пару минут все стабилизируется
  2. Никаких предметов не потеряно, хотя
  3. Танец происходит только при первой синхронизации iCloud 2-го (или любого другого последующего устройства)
  4. Если второе устройство запускается онлайн в первый раз, вероятность появления случая с дублирующимися категориями составляет всего около 25% - проверено на соединении 3G - поэтому танец не должен влиять на большинство пользователей
...