#macos #cocoa #itunes #cocoa-bindings #nsoutlineview
#macos #cocoa #iTunes #привязки cocoa #nsoutlineview
Вопрос:
Я хочу отобразить некоторые элементы на своей боковой панели, при этом также будет отображаться количество каждого тега:
Как мне сделать это эффективно и автоматически? Простым вариантом было бы использовать привязки cocoa, но я не уверен, как лучше всего это сделать: нужен ли для каждой кнопки собственный NSArrayController с предикатом выборки, установленным для «тега»? Это может привести к X количеству NSArrayControllers (по одному для каждого тега), что было бы довольно тяжелым (я бы подумал).
Другой вариант — создавать запросы на выборку вручную, а затем выполнять повторную выборку для каждого изменения в контексте управляемого объекта. Но это кажется немного запутанным и не автоматическим.
Есть ли более простое решение для этого? Я поискал в Google и ничего не нашел.
Комментарии:
1. Боковая панель содержит NSTableView??
2. ДА. Если быть точным, NSOutlineView.
Ответ №1:
Давайте предположим, что в вашем NSOutlineView у вас есть childrenKeyPath «дочерних элементов», а дочерние элементы имеют логический атрибут isNew. То, что вам нужно, — это хороший numberOfNewItems
пузырь в представлении ячейки для одного класса объектов. Я буду называть это родительским объектом.
Если вам просто нужно количество объектов в childrenKeyPath, черт возьми, это еще проще, но я проведу вас через более сложный случай отслеживания определенного логического свойства для дочерних элементов, потому что достаточно легко упростить этот шаблон.
В представлении ячейки таблицы для родительского объекта добавьте утопленную кнопку с привязкой к заголовку objectValue.numberOfNewItems
и скрытой привязкой к objectValue.NumberOfNewItems
преобразователю значений NSNegateBoolean. Если вам просто нужно количество дочерних элементов, измените эти пути к objectValue.children.count
клавишам, и все готово. Если вы хотите отслеживать свойство, подобное isNew, давайте продолжим…
В классе родительских объектов есть этот код:
- (NSNumber*) numberOfNewItems
{
// Collection operator on boolean returns total number of new children
return [self valueForKeyPath:@"children.@sum.isNew"];
}
// This setter does nothing, but with KVO it causes bindings
// to numberOfNewItems to call the above getter
- (void) setNumberOfNewItems:(NSNumber*)number { }
// This ensures that changes to the children set causes KVO calls to the above getter
(NSSet*) keyPathsForValuesAffectingNumberOfNewItems
{
return [[NSSet alloc] initWithObjects:@"children", nil];
}
Что это делает, так это приводит numberOfNewItems
к пересчету в любое время, когда objectValue ячейки таблицы получает новый дочерний элемент, добавленный или удаленный из отношения « children
ко многим».
В классе ChildItem это есть в одном месте, где дочерний элемент переходит из нового в не новый:
// If collapsing an item, mark it as not new
if (!isExpanded.boolValue amp;amp; self.isNewValue) {
self.isNew = @NO;
[self.parent setNumberOfNewItems:nil]; // Triggers KVO for button binding
}
… и что это делает, так это использует пустой установщик setNumberOfNewItems родительского setNumberOfNewItems, чтобы заставить привязку кнопки вызывать средство получения. Таким образом, все children
отношения «ко многим» перечисляются каждый раз, когда элемент помечается как не новый. Я предполагал, что это можно улучшить, но я еще не играл с этим.
Я воспользовался тем фактом, что элемент помечен как не новый только в одном месте в моем коде. Если у вас есть несколько настроек для сброса или настройки isNew в дочернем элементе, вы можете переопределить setIsNew в классе ChildItem для вызова self.parent setNumberOfNewItems:nil
вместо этого.
Хитрость здесь в том, что добавление родительского элемента в качестве наблюдателя KVO для isNew keypath для всех дочерних элементов было бы ужасной болью. Поэтому я хотел избежать этого. Если у вас просто есть дочерние элементы, вызывающие пустой параметр в родительском элементе, родительский элемент может владеть вычислением, и нет KVO вне того, что используют привязки.
Выглядит так: