2013-07-10 3 views
10

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

Когда я обновить этот объект в фоне (частные очереди типа параллелизм) контекста, а затем объединить сохраненные изменения в моей основной контекст очереди (в mergeChangesFromContextDidSaveNotification), КВО уведомления огня, как и ожидалось.

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

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

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

+0

Как вы обрабатываете уведомление? Вы должны смотреть на NSUpdatedObjectsKey словаря пользовательской информации уведомления. – random

+0

Я реализовал этот метод: - (void) observValueForKeyPath: (NSString *) keyPath ofObject: (id) изменение объекта: (NSDictionary *) изменить контекст: (void *) context; – aloo

+0

Теперь я мог бы взглянуть на словарь изменений и посмотреть на старое значение, чтобы увидеть, изменилось ли оно с текущего значения - но почему я получаю уведомление KVO в первую очередь, если nsmanagedobject даже не изменился для данного ключа? – aloo

ответ

3

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

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

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

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

+0

Спасибо за отличный ответ. Любые ссылки, которые подтверждают, что это известная проблема для нескольких человек? Просто хочу, чтобы я не делал что-то неправильно. Я собираюсь пойти по пути проверки уведомления KVO, чтобы узнать, отличается ли новое значение от нового значения - если да, то обновите интерфейс. – aloo

+0

См., Например, эту открытую радарную ошибку - http://openradar.appspot.com/6624874 - ваше использование KVO на сохраненном объекте фактически равно его решению 3. –

+1

Кроме того, документация по KVO Compliance - http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/KeyValueObserving/Articles/KVOCompliance.html - заявляет, что уведомление на каждом setValue является значением по умолчанию, если вы не пишете конкретный код для проверки изменений. Вероятно, команда Core Data написала, что для каждого возможного типа полей Core Data и вызывает соответствующий компаратор для каждого поля каждого объекта при каждом сохранении, как это было бы необходимо для того, чтобы KVO на сохраненных объектах работал так, как вы надеялись? ... naah, нет, это не так. –

0

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

+0

Я не хочу жестко кодировать ключи, для которых я хочу получать уведомления. Я хочу, чтобы уведомления отправлялись ТОЛЬКО ключей, которые фактически изменились после слияния. В настоящее время я получаю уведомления о ключах, которые даже не менялись. – aloo

Смежные вопросы