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

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

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

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


person Donald    schedule 30.07.2010    source источник


Ответы (1)


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

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

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