Выборка Coredata не возвращает результат, только что записанный в хранилище

Сценарий:

Я использую IOS, используя запись Magical, настроенную для работы с базой данных SQLite. По умолчанию MR настраивает coredata для сериализации всех записей обратно в родительский контекст в основном потоке.

Шаблон, который я использую, заключается в том, что когда я не в основном потоке, я создаю отдельный NSManagedObjectContext для операций с основными данными, используя что-то вроде MagicalRecord:MR_saveWithBlockAndWait. Волшебная запись создает контекст, подключает его к родительскому контексту, выполняет любые операции, которые вы указываете в блоке обратного вызова, и, наконец, сохраняет. Важно отметить, что сохранение должно быть зафиксировано до завершения операции.

Когда я заканчиваю работу с фоновым потоком, я обычно уведомляю пользовательский интерфейс о том, что что-то произошло; например: что-то загружается/загружается/изменяется.

Затем в потоке пользовательского интерфейса я создаю новый запрос на выборку, используя контекст по умолчанию в основном потоке. Проблема в том, что иногда coredata не находит новый объект, который я только что зафиксировал ранее. Проблема проявляется в сложных условиях гонки, когда, если поток пользовательского интерфейса немного замедляется из-за анимации или чего-то еще, все работает нормально, но иногда он не находит новый объект.

Из того, что я прочитал, запросы на выборку всегда должны отправляться на диск. В MOC также есть свойство устаревания, но похоже, что оно касается только кеша и игнорируется, если вы выполняете запрос на выборку.

Кто-нибудь сталкивался с подобными проблемами и имеет какие-либо идеи? Благодарю.


person harshaw    schedule 15.10.2013    source источник


Ответы (1)


Конечно. Если вы сохраняете изменения в контексте фонового управляемого объекта, но ваш контекст пользовательского интерфейса уже загрузил этот объект, контекст пользовательского интерфейса может просто предоставить вам данные из своего кэша, а не из файла хранилища.

Обычный подход к использованию нескольких контекстов:

  1. Соблюдайте NSManagedObjectContextDidSaveNotification, чтобы знать, когда фоновый контекст сохраняет изменения.

  2. В обработчике этого уведомления вызовите mergeChangesFromContextDidSaveNotification: в контексте пользовательского интерфейса, чтобы он обновлялся с учетом изменений из другого контекста.

Вы, вероятно, захотите установить mergePolicy в контексте своего пользовательского интерфейса, потому что по умолчанию нужно просто сдаться, если есть какие-либо конфликтующие изменения.

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

person Tom Harrington    schedule 15.10.2013
comment
Конечно, и я думаю, что это имело бы смысл, если бы я сказал основным данным сохранять и хотел получить предупреждение, когда запись сбрасывается. ОДНАКО, мое прочтение кода MR заключается в том, что когда вы вызываете MR_savewithBlockAndWait... он фактически ожидает завершения записи. - person harshaw; 16.10.2013
comment
Вы упускаете суть. Необходимость слияния изменений не имеет абсолютно никакого отношения к тому, завершилось ли сохранение. Это связано с контекстом управляемого объекта, использующим кешированные данные, и вам нужно сообщить ему, что некоторые из этих данных изменились. - person Tom Harrington; 16.10.2013
comment
и нет способа просто сказать coredata читать из Sqlite и обходить его кеши? Проблема заключается в следующем: поскольку объект coredata вставляется/обновляется/удаляется, он не сообщает вам, что имел в виду пользователь. Вот почему у нас есть обмен сообщениями более высокого уровня. Похоже, мне нужно было бы отбросить сообщение в потоке пользовательского интерфейса, в котором говорится, что следующее изменение слияния связано с тем, что пользователь изменил цвет изображения, а ТОГДА ждать уведомления о слиянии. Кажется, это созрело для состояния гонки. - person harshaw; 16.10.2013
comment
Также есть метод refreshObject:mergeChanges:. Вызовите это для каждого объекта, который вы хотите обновить, с NO в качестве второго аргумента, а затем повторно выберите объект. Как правило, это намного больше работы, но это возможно. - person Tom Harrington; 16.10.2013