0

У меня есть объект, который реализует индексированные методы доступа для ключа с именем contents. В тех аксессуарах я вызываю willChange:valuesAtIndexes:forKey: и didChange:valuesAtIndexes:forKey:, когда я изменяю базовый массив.observValueForKeyPath: ofObject: change: context: не работает должным образом с массивами

У меня также есть объект пользовательского вида, который связан с contents через NSArrayController. В observeValueForKeyPath:ofObject:change:context: значение только в словаре изменений для NSKeyValueChangeKindKey Я когда-либо видел NSKeyValueChangeSetting. Когда я добавляю объекты в массив, я ожидаю увидеть NSKeyValueChangeInsertion.

Воспроизведение внутреннего представления объектов, которое он наблюдает каждый раз, когда я вставляю один элемент - особенно когда я загружаю сотни предметов, - представляет довольно сложную задачу, как вы могли себе представить. Что я делаю неправильно, что Cocoa, кажется, думает, что я устанавливаю совершенно новый массив каждый раз, когда я добавляю или удаляю один элемент?

ответ

0

У меня есть объект, который реализует индексированные методы доступа для ключа, называемого содержимым. В этих аксессуарах я вызываю willChange: valuesAtIndexes: forKey: and didChange: valuesAtIndexes: forKey: когда я изменяю базовый массив.

Не делайте этого. KVO отправляет уведомления для вас, когда вы получаете сообщение одному из этих аксессуаров.

У меня также есть пользовательский объект вида, связанный с содержимым через NSArrayController. В watchValueForKeyPath: ofObject: change: context: единственное значение в словаре изменений для NSKeyValueChangeKindKey, которое я когда-либо видел, это NSKeyValueChangeSetting. Когда я добавляю объекты в массив, я ожидаю увидеть NSKeyValueChangeInsertion.

С одной стороны, почему вы используете KVO напрямую? Используйте bind:toObject:withKeyPath:options:, чтобы привязать свойство view к свойству класса arrangedObjects контроллера массива (предположим) и реализовать в представлении средства доступа к массиву (включая индексированные аксессоры, если хотите).

Для другого, помните, что arrangedObjects является производным свойством. Контроллер массива будет фильтровать и сортировать свой массив содержимого; результатом является arrangedObjects. Вы можете утверждать, что перестановка индексов из первоначальной вставки в новую вставку будет более точным переводом первого изменения во второе, но установка всего массива arrangedObjects, вероятно, была проще реализовать (что-то вроде [self _setArrangedObjects:[[newArray filteredArrayUsingPredicate:self.filterPredicate] sortedArrayUsingDescriptors:self.sortDescriptors]]).

Действительно ли это имеет значение? Профилировали ли вы и обнаружили, что ваше приложение работает медленно с заменой оптового массива?

Если это так, вам может потребоваться привязать представление непосредственно к свойству массива content или к исходному массиву на базовом объекте и получить потерю свободной фильтрации и сортировки.

0

Я вызываю методы KVO вручную по причинам, выходящим за рамки этой проблемы. Я отключил автоматическое наблюдение за этим свойством. Я знаю, что я там делаю.

Я не понимаю, что вы подразумеваете, реализуя аксессоры блоков в представлении. Привязки строятся поверх KVO. Все привязки реализованы с использованием observeValueForKeyPath:. Мое пользовательское представление обеспечивает привязку, которую приложение связывает с массивом - или в этом случае - с контроллером массива. Методы доступа применяются к KVC, а не к KVO.

Совершенно важно, чтобы я получал заданное сообщение для каждого обновления массива. Я бы не опубликовал его как вопрос, если бы это не имело значения. Я называю что-то вроде

[[modelObject mutableArrayValueForKey:@"contents"] addObjectsFromArray:hundredsOfObjects]; 

На каждой вставке мой взгляд наблюдает за целым новым массивом. Поскольку я потенциально добавляю сотни объектов, это O(N^2), когда это должно быть O(N). Это совершенно неприемлемо, проблемы с производительностью. Но, поскольку вы упомянули об этом, представление действительно должно сделать достаточную работу для наблюдения за всем новым массивом, что значительно замедляет работу программы.

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

Я решил проблему с полным взломом. Я написал отдельный метод, который вызывает методы KVO вручную, так что отправляется только одно сообщение KVO. Это взломать, мне это не нравится, и это все еще заставляет меня перечитать весь массив - хотя только один раз, сейчас - но сейчас это работает, пока я не выясню лучшее решение.

1

(Примечание для всех читателей: Я ненавижу использовать ответы для этого тоже, но эта дискуссия слишком длинная для комментариев. Недостатком, конечно же, является то, что она не сортируется в хронологическом порядке. Если вам это не нравится , Я предлагаю вам жаловаться на администраторов Stack Overflow о комментариях с ограничениями по длине и только для текстового текста.)

Я не понимаю, что вы подразумеваете, реализуя аксессоры блоков в представлении.

Внедрение аксессуаров, включая индексированные аксессоры, для свойства изменяемого массива, которое вы выставили в качестве привязки.

Привязки строятся на крыше KVO.

И KVC.

Все переплеты выполнены с использованием observeValueForKeyPath:

Переопределение, что является одним из способов, конечно. Другой способ - реализовать аксессоры в объекте со свойством bindable (представление).

Мое пользовательское представление обеспечивает привязку, которую приложение связывает с массивом или в этом случае контроллером массива. Методы доступа применяются к KVC, а не к KVO.

Какао-привязки вызовут для вас аксессуры вашего вида (предположительно, используя KVC). Вам не нужно реализовывать метод наблюдения KVO (если, конечно, вы не используете KVO напрямую).

Я знаю это, потому что я сделал это таким образом. См. PRHGradientView в CPU Usage.

Любопытно, что в документации это не упоминается. Я собираюсь записать ошибку в документации - либо я делаю что-то хрупкое, либо забыл упомянуть эту очень приятную функцию в документах.

Совершенно важно, чтобы я получал заданное сообщение для каждого обновления массива. Я бы не опубликовал его как вопрос, если бы это не имело значения.

Есть довольно много людей, которые занимаются чем-то, что называется «преждевременной оптимизацией». Я не знаю, кто из них, не спрашивая.

+0

Да, это не документировано вообще. Я никогда не видел этого раньше, в том числе и в любом из примеров, которые я видел. Возможно ли это после Пантеры? – Alex

+0

Да, это всегда сработало для меня. Я зарегистрировал ошибку в документации: x-radar: // problem/6588723 (http://openradar.appspot.com/6588723). –