Блоки GCD не обновляют NSCollectionView

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

Щас пользуюсь addObserverForName:object:queue:usingBlock зарегистрироваться для уведомлений, и это работает нормально (как массив и NSCollectionView обновляются) когда я указал [NSOperationQueue mainQueue] для очереди. Однако, когда я создал свою очередь (используя [[NSOperationQueue alloc] init]), то NSCollectionView прекращает обновление. Используя отладчик, я вижу, что обновляемый массив обновляется.

Это ошибка, или я что-то здесь упустил?

1 ответ

При работе с привязками AppKit любые уведомления KVO, которые публикуются, должны появляться в главном потоке, чтобы все работало правильно. Таким образом, если вы измените массив непосредственно из вашего обработчика уведомлений в фоновом потоке, NSCollectionView будет получать любые инициированные уведомления KVO в этом потоке, а не в основном потоке. Поведение, когда это происходит, не определено, и в лучшем случае не будет работать, в то время как в худшем случае может вызвать сбои или другое странное поведение.

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

  • Взгляните на NSNotificationQueue (не имеет отношения к NSOperationQueue), который поддерживает объединение нескольких опубликованных NSNotification в одно уведомление, отправленное вашему наблюдателю.
  • Слушайте уведомления в фоновом режиме, как вы делаете, но собирайте изменения самостоятельно, возможно, публикуйте только каждое N-е изменение или запускайте таймер, чтобы опубликовать обновление, если больше не поступило в течение X времени. Затем, когда вы выполняете фактическое обновление массива, попытайтесь сузить его до минимума, насколько это возможно, а затем перенесите это в основной поток. призвание -[NSOperationQueue addOperationWithBlock:] на mainQueue это простой способ сделать это.
Другие вопросы по тегам