Чтобы эффективно задать вопрос, позвольте сначала рассмотреть точный сценарий, с которым я сталкиваюсь:
Общая настройка
- Приложение хоста iOS 8.
- Один или несколько расширений iOS 8 (WatchKit, Share и т.д.) в комплекте с хост-приложением.
- Приложение-хост и все расширения совместно используют одно хранилище данных SQLite в общем контейнере группы приложений.
- Каждое приложение/расширение имеет собственный NSPsistentStoreCoordinator и NSManagedObjectContext.
- Каждый постоянный координатор хранилища использует постоянное хранилище, которое использует те же ресурсы SQLite в контейнере группы, что и все остальные постоянные хранилища.
- Приложение и все расширения используют общую кодовую базу для синхронизации содержимого с удаленного ресурса API в Интернете.
Последовательность событий, ведущих к проблеме
-
Пользователь запускает хост-приложение. Он начинает получать данные из удаленного ресурса API. Объекты модели основных данных создаются на основе ответа API и "обновлены" в контексте объекта управляемого приложения. Каждый объект API имеет уникальный идентификатор, который идентифицирует его в удаленном интерфейсе API. Под "upsert" я подразумеваю, что для каждого объекта API приложение-хозяин создает новую запись в Core Data, если существующая запись для данного уникального идентификатора не может быть найдена.
-
Между тем пользователь также запускает одно из расширений хост-приложений. Он также выполняет какую-то выборку из того же удаленного API. Он также пытается выполнить "upsert" при анализе ответов API.
-
Проблема: Что произойдет, если и хост-приложение, и расширение попытаются одновременно обновить запись Core Data для одного и того же объекта API? Чтобы узнать, как это может произойти, давайте посмотрим на последовательность событий для upsert:
Последовательность обновления основных данных:
- Код анализа API анализирует уникальный идентификатор для данного объекта API.
- Анализатор выполняет выборку основных данных для любой записи, которая соответствует предикату, где
uniqueID
равна разобранному уникальному идентификатору. - Если существующая запись не найдена, анализатор вставляет новую запись Core Data для этого объекта API, устанавливает свой атрибут
uniqueID
в разобранный уникальный идентификатор. - Анализатор сохраняет контекст управляемого объекта, который подталкивает новые данные ввода в хранилище резервных копий SQLite.
Проблема в деталях
Предположим, что приложение-хозяин и расширение самостоятельно анализируют ответ API для одного и того же объекта API в одно и то же время. Если и хост-приложение, и расширение достигнут шага 3 до того, как любой из них завершит Шаг 4, они оба попытаются вставить новую запись Core Data для того же уникального идентификатора. Когда они достигнут шага 4 и вызовут save:
в соответствующих контекстах управляемых объектов, Core Data с радостью создаст повторяющиеся записи.
Насколько мне известно, Core Data не имеет возможности пометить атрибут как уникальный. Мне нужен Core Data эквивалент SQLite INSERT OR IGNORE
+ UPDATE
комбо.. Или мне нужен способ "заблокировать" хранилище резервных хранилищ SQLite, которое звучит как рецепт проблемы.
Есть ли известный подход к этой довольно новой проблеме, введенной расширениями iOS 8?