Блоки 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 это простой способ сделать это.