Уведомления KVO после mergeChangesFromContextDidSaveNotification

Я использую KVO для наблюдения за изменениями в объекте NSManagedObject. Наблюдаемый NSManagedObject является частью контекста NSManagedObject, который находится в главной очереди.

Когда я обновляю этот объект в контексте фона (private queue concurrency type), а затем объединяю сохраненные изменения в мой основной контекст очереди (в mergeChangesFromContextDidSaveNotification), уведомления KVO срабатывают, как ожидалось.

Однако я ожидал, что уведомления будут срабатывать только для основных путей, которые фактически были изменены, а не для всех ключевых путей NSManagedObject. Я получаю уведомления KVO для каждого ключевого пути моего объекта, даже если они не меняются.

Является ли это по дизайну или я делаю что-то неправильно?

В яблочных документах ничего не видно....

Ответ 1

Это недокументированное, но наблюдаемое поведение как для OS X, так и для iOS, что сохранение считается изменением для всего NSManagedObject, а не только с разными элементами. Вы можете найти ворчания о различных последствиях этого для привязок и т.д. Вокруг этого сайта, на openradar.appspot.com и т.д. То, что проблема также проявляется с явно ложными выстрелами KVO, совершенно неудивительно.

Самый простой способ справиться с проблемой (ну, проще всего, "просто перерисовать все на сохранении", на котором я нахожу отличный вариант первого прохода до тех пор, пока кто-то не пожалуется), это прослушивание общего уведомления о сохранении, а затем вызов -changedValues ​​для каждого обновленного объект, чтобы выбрать те, которые вам интересны, для активации определенных обновлений.

Если это безнадежно неэффективно для вашего прецедента, вы можете сделать пользовательские аксесуары (mogenerator - большая помощь с этим) для ваших свойств, которые собирают флаги потока редактирования для изменений во всех интересующих вас свойствах; и отправьте это как уведомление после сохранения.

Давайте, например, скажем, что приложение для профессиональных спортивных команд, которое постоянно обновляется с помощью фидов JSON, проанализированных в фоновом режиме. Все атрибуты, влияющие на отображение различных команд, игроков, игр и т.д. У NSManagedObjects есть пользовательские аксессоры, которые устанавливают флаги в структуре {playerStatsChanged, teamStatsChanged, leagueRankingsChanged, yadayadayadaChanged}, в соответствии с тем, какие страницы в приложении будут нуждаться в повторном отображении после текущей выборки -and-parse thread завершается. Затем, как только он будет сохранен, он отключит общее уведомление об обновлении этих экранов с помощью этой структуры установки флага. Вероятно, вы, возможно, объединяете индивидуальные уведомления об изменении пути в какой-то более высокий уровень "обновляете этот экран" в любом случае, верно? Ну, на уровне сеттера свойств это самый низкий накладной пункт, который вы можете сделать для большинства разумных вариантов использования. Конечно, для любой повторяющейся модели обновления, такой как наши приложения для спортивных команд здесь.

Ответ 2

Вы можете переопределить автоматические уведомления об изменениях с помощью ручных уведомлений только для ключей по вашему выбору. Ознакомьтесь с подробной документацией здесь.