iCloud + CoreData — как избежать дублирования предварительно заполненных данных?

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

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

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

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

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

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

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

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

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

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

[moc mergeChangesFromContextDidSaveNotification: note];

Я звоню

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

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

materializeKeysWithUserInfo:forContext:

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

Стратегия 1:

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

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

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

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

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

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

Стратегия 2:

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

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

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

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

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

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

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

Стратегия 3

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

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

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


person Kostiantyn Sokolinskyi    schedule 01.02.2012    source источник


Ответы (1)


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

Легенда:

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

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

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

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

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

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

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

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

  • Переместите их элементы, если таковые имеются, в старые повторяющиеся категории.

  • Удалить новые повторяющиеся категории

При добавлении новых элементов — если элемент относится к категории удалено:

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

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

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

ВУАЛЯ! - никаких дубликатов и все довольны

Пара замечаний:

  1. Я получаю танец предметов, принадлежащих 2-му устройству (те, которые придут с нулевой категорией на 1-е устройство) на обоих устройствах. Через пару минут все стабилизируется
  2. Хотя ни один предмет не пропал
  3. Танец происходит только при первой синхронизации iCloud со вторым (или любым другим последующим устройством)
  4. Если 2-е устройство запускается в сети в первый раз, вероятность появления повторяющихся категорий составляет всего около 25 % — протестировано на 3G-соединении — поэтому танец не должен влиять на большинство пользователей.
person Community    schedule 03.02.2012
comment
Константин, я следил за вашими разговорами на dev. сайт. Я очень ценю, что вы добавили вопрос здесь - я хотел бы, чтобы было больше комментариев! Эта стратегия сработала для вас? Рассматривали ли вы предварительно созданный localStore, как в образце SharedCoreData? С Уважением - person ICL1901; 02.01.2013
comment
Вы можете переименовывать свои категории, если вы можете различать записи, созданные системой, и записи, созданные пользователями. Я использовал пару атрибутов createDate и updateDate, чтобы определить, следует ли определять элемент данных. дублируется. - person adib; 07.12.2013
comment
Привет, ребята, мне пришлось остановиться в какой-то момент 2 года назад, и с тех пор я не возвращался к CoreData + iCloud. @adib - спасибо за ваш комментарий. Я бы использовал эту технику позже, если бы это было необходимо. - person Kostiantyn Sokolinskyi; 07.12.2013