-addObserver
消息。显然我没有正确绑定到这个阵列控制器。我想我错过了关于表视图列如何绑定到数组的基本信息。
在一些重构期间出现了这个问题。我曾经在nib中实例化数组控制器。该文档是文件所有者,并具有阵列控制器的插座。绑定看起来像我的阵列控制器> arrangeObjects>的attributeName 即可。一切都很好。
由于文档处理通过数组控制器插入对象,我不认为窗口控制器应该负责创建它。窗口控制器是新的笔尖所有者,所以我从笔尖中删除了它。我现在在-makeWindowControllers
的代码中创建它。 (我问过related question about initialization。)
调试时我发现了别的东西。如果窗口控制器是表视图的数据源,我实现-numberOfRowsInDataSource
:
return [[self.document._arrayController arrangedObjects] count];
表视图调用它,为所有列发送-addObserver
消息,并使用绑定实际加载每个单元格的值。但是,在为给定单元格加载值时,不是在arrangedObjects
中加载第n个对象的属性值,而是为整个对象列加载属性值。它将这些数组传递给值变换器(无法正确处理它们)并在文本单元格中显示数组description
(它们不适合)。
当窗口控制器是表视图的数据源但列使用绑定时,表视图应忽略-numberOfRowsInTableView
的结果,或者根本不应该调用它。 (使用return 0
响应选择器只是为了避免运行时错误。数据源仅在第一时间设置,以实现单元格的工具提示。)同样,所有这些都用于工作我在笔尖中创建数组控制器时很好。
一些想法:
加了:
我使用表视图数据源以及绑定的原因是使用以下方法实现拖放重新排序:
tableView:writeRowsWithIndexes:toPasteboard:
tableView:validateDrop:proposedRow:proposedDropOperation:
tableView:acceptDrop:row:dropOperation:
答案 0 :(得分:1)
一些想法:
首先,您不应该同时实现NSTableViewDataSource协议和使用绑定 - 它通常是一个或另一个。如果您有特定的理由这样做,我会首先使用绑定启动您的应用程序,然后一步一步地从NSTableViewDataSource分层您想要的任何功能,以确保一切正常。有可用于支持工具提示的绑定。
接下来,我不是说这是唯一的方法,但我建议将ArrayController放回xib中。 NSController子类与绑定它们的控件之间似乎存在特殊关系 - 绑定检查器中的Controller Key:条目强烈暗示这一点,因为当您不使用它时它被禁用。我不确定,但我猜测当你通过那个大的keyPath绑定到达文档来获取arrayController时,那种魔力就不会发生了。
我也想知道为什么你会希望NSArrayController住在除了控件绑定到它的窗口之外的某个地方?相关的原因是你将WindowController 与文件共享 NSArrayController?
NSArrayControllers保持选择状态,所以确实每个窗口有一个,或者更抽象地说,它们会靠近UI,因此应该存在于每个需要一个的nib中。也就是说,除非你试图做一些非传统的事情,比如在多个窗口之间共享一个选择状态(即改变窗口A中的选择和窗口B中的相应控件也改变选择以匹配窗口A)。我将在下面探讨一下,但简而言之,我想不出你想要共享一个arrayController而不是将多个arrayControllers绑定到相同的底层数据的任何其他原因。
如果选择共享是你的目标,我认为你最好做一些事情,比如让文档在每个窗口中的nib创建的ArrayControllers的selectionIndexes上设置Key-Value Observances并让它们将选择传播到其他windows的arrayControllers。
我把它编码了;它似乎工作。我从Xcode开始使用标准的基于NSDocument的Cocoa应用程序模板,并在文档中添加了dataModel
属性,并用一些数据伪造了它。然后我在makeWindowControllers
期间制作了两个窗口,然后我添加了观察等,以使他们的选择相互跟随。一切似乎很好地融合在一起。
加入一个代码块:
#import <Cocoa/Cocoa.h>
@interface SODocument : NSDocument
@property (retain) id dataModel;
@end
@interface SOWindowController : NSWindowController
@property (retain) IBOutlet NSArrayController* arrayController;
@end
@implementation SODocument
@synthesize dataModel = _dataModel;
- (id)init
{
self = [super init];
if (self)
{
// Make some fake data to bind to
NSMutableDictionary* item1 = [NSMutableDictionary dictionaryWithObjectsAndKeys: @"Item 1", @"attributeName", nil];
NSMutableDictionary* item2 = [NSMutableDictionary dictionaryWithObjectsAndKeys: @"Item 2", @"attributeName", nil];
NSMutableDictionary* item3 = [NSMutableDictionary dictionaryWithObjectsAndKeys: @"Item 3", @"attributeName", nil];
_dataModel = [[NSMutableArray arrayWithObjects: item1, item2, item3, nil] retain];
}
return self;
}
- (void)dealloc
{
[_dataModel release];
[super dealloc];
}
- (NSString *)windowNibName
{
return @"SODocument";
}
- (void)makeWindowControllers
{
SOWindowController* wc1 = [[[SOWindowController alloc] initWithWindowNibName: [self windowNibName]] autorelease];
[self addWindowController: wc1];
SOWindowController* wc2 = [[[SOWindowController alloc] initWithWindowNibName: [self windowNibName]] autorelease];
[self addWindowController: wc2];
}
- (void)addWindowController:(NSWindowController *)windowController
{
[super addWindowController: windowController];
[windowController addObserver:self forKeyPath: @"arrayController.selectionIndexes" options: 0 context: [SODocument class]];
}
- (void)removeWindowController:(NSWindowController *)windowController
{
[windowController removeObserver:self forKeyPath: @"arrayController.selectionIndexes" context: [SODocument class]];
[super removeWindowController:windowController];
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([SODocument class] == context && [@"arrayController.selectionIndexes" isEqualToString: keyPath])
{
NSIndexSet* selectionIndexes = ((SOWindowController*)object).arrayController.selectionIndexes;
for (SOWindowController* wc in self.windowControllers)
{
if (![selectionIndexes isEqualToIndexSet: wc.arrayController.selectionIndexes])
{
wc.arrayController.selectionIndexes = selectionIndexes;
}
}
}
}
@end
@implementation SOWindowController
@synthesize arrayController = _arrayController;
-(void)dealloc
{
[_arrayController release];
[super dealloc];
}
@end
文档笔尖有一个SOWindowController的文件所有者。它有一个绑定到File's Owner.document.dataModel
的NSArrayController,以及一个绑定到ArrayController.arrangedObjects.attributeName
的列的NSTableView。
当我创建一个新文档时,会出现两个窗口,每个窗口都显示相同的内容。当我将tableView选项更改为一个时,另一个也会更改。
无论如何,希望这有帮助。