我想使用带有NSTableView
的{{1}}来允许多项选择,但仅在选择单个对象时提供所选对象(如果未选择任何一个或多个,则nil
)。
我尝试使用NSArrayController
上的类别实现此功能,如下所示:
@implementation NSArrayController (SelectedObject)
+ (NSSet *)keyPathsForValuesAffectingSelectedObject {
return [NSSet setWithObject:@"selection"];
}
- (id)selectedObject {
// Get the actual selected object (or nil) instead of a proxy.
if (self.selectionIndexes.count == 1) {
return [self arrangedObjects][self.selectionIndex];
}
return nil;
}
@end
由于某种原因,当数组控制器的选择发生变化时(而其他东西正在观察selectedObject
),不会调用selectedObject
方法。这是为什么?
答案 0 :(得分:1)
selection
的{{1}}属性是奇怪的伏都教。我不知道键值是否观察它(而不是通过通过它的路径)在选择发生变化时会产生更改通知。毕竟,它返回一个代理,没有理由相信该代理的身份会随着时间而变化。
在任何情况下,您的实际NSArrayController
方法实际上并未使用selectedObject
(它不应该使用)。它使用selection
和arrangedObjects
。因此,您应该从selectionIndexes
返回包含那些键的集合。
当然,如果您使用的是基于视图的表,则需要确保表视图的+keyPathsForValuesAffectingSelectedObject
绑定绑定到数组控制器的selectionIndexes
属性,或者只是赢得了数组控制器在表格视图中对选择一无所知。 (对于基于单元格的表视图,通常将列绑定到数组控制器,表视图将根据列的绑定自动绑定其自己的绑定。)
最后,我认为你应该为selectionIndexes
选择一个不同的名称。 Apple有可能拥有该名称的私有方法,或者将来会添加一个。
答案 1 :(得分:0)
我设法通过创建NSArrayController
的子类并手动观察selectionIndexes
键来实现此功能。我更喜欢使用类别来做这件事,但这看起来确实有效。
static NSString *const kObservingSelectionIndexesContext = @"ObservingSelectionIndexesContext";
@implementation BetterArrayController
- (void)awakeFromNib {
[super awakeFromNib];
[self addObserver:self forKeyPath:@"selectionIndexes" options:NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew context:(void *)&kObservingSelectionIndexesContext];
}
- (void)dealloc {
[self removeObserver:self forKeyPath:@"selectionIndexes" context:(void *)&kObservingSelectionIndexesContext];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (context == (void *)&kObservingSelectionIndexesContext) {
[self willChangeValueForKey:@"selectedObject"];
[self didChangeValueForKey:@"selectedObject"];
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (id)selectedObject {
// Get the actual selected object (or nil) instead of a proxy.
if (self.selectionIndexes.count == 1) {
return [self arrangedObjects][self.selectionIndex];
}
return nil;
}
@end
我使用了一个上下文(根据this article)来避免移除超类在dealloc
中可能拥有的任何观察者(正如here所提醒的那样)。