gpt4 book ai didi

cocoa - 将数组 Controller 初始化从 nib 移动到代码会破坏 TableView 绑定(bind)

转载 作者:行者123 更新时间:2023-12-03 16:43:52 25 4
gpt4 key购买 nike

  1. 我的窗口 Controller 子类是 Nib 的所有者。
  2. 我在文档子类中用代码实例化了我的数组 Controller 。文档和窗口 Controller 都在代码中使用它。
  3. 我像这样绑定(bind)表列:文件所有者>> document._arrayController.arrangedObjects.attributeName
  4. 表格 View 不显示任何行。
  5. 窗口 Controller 和文档类都不会接收与 TableView 相关的 -addObserver 消息。

显然我没有正确绑定(bind)到这个数组 Controller 。我认为我遗漏了有关 TableView 列如何绑定(bind)到数组的一些基本知识。

这个问题是在一些重构过程中出现的。我曾经在 Nib 中实例化数组 Controller 。该文档是文件所有者,并且有一个阵列 Controller 的导出。绑定(bind)看起来像My Array Controller >arrangedObjects > attributeName。一切正常。

由于文档通过数组 Controller 处理插入对象,因此我认为窗口 Controller 不应该负责创建它。窗口 Controller 是新的 Nib 所有者,因此我将其从 Nib 中删除。我现在在 -makeWindowControllers 中的代码中创建它。 (我问了这个related question about initialization。)

在调试这个问题时我发现了一些其他的东西。如果窗口 Controller 是 TableView 的数据源并且我实现 -numberOfRowsInDataSource:

return [[self.document._arrayController arrangedObjects] count];

TableView 调用它,为所有列发送 -addObserver 消息,并使用绑定(bind)实际加载每个单元格的值。但是,当加载给定单元格的值时,它不会加载 arrangedObjects 中第 n 个对象的属性值,而是加载整个对象列的属性值。它将这些数组传递给值转换器(无法正确处理它们),并在文本单元格中显示数组的描述(它们不适合在其中)。

当窗口 Controller 是 TableView 的数据源但列使用绑定(bind)时, TableView 应该忽略 -numberOfRowsInTableView 的结果,或者根本不应该调用它。 (使用 return 0 响应选择器只是避免了运行时错误。数据源仅首先设置以实现单元格的工具提示。)同样,所有当我在 Nib 中创建数组 Controller 时,这曾经工作得很好。

一些想法:

  1. 是否可以使用 IB 将表列绑定(bind)到另一个对象拥有的数组 Controller ?
  2. 我是否需要将数组 Controller 放回 Nib ,并让窗口 Controller 与文档实例共享它? (这听起来像是可怕的设计。)
  3. 我应该有两个数组 Controller ,一个用于窗口 Controller ,另一个用于文档?
<小时/>

已添加:

我使用 TableView 数据源和绑定(bind)的原因是使用这些方法实现拖放重新排序:

  • tableView:writeRowsWithIndexes:toPasteboard:
  • tableView:validateDrop:proposedRow:proposedDropOperation:
  • tableView:acceptDrop:row:dropOperation:

最佳答案

一些想法:

首先,您不应该同时实现 NSTableViewDataSource 协议(protocol)使用绑定(bind)——通常是其中之一。如果您有特定的原因这样做,我会首先使用绑定(bind)来启动并运行您的应用程序,然后一次一步地从 NSTableViewDataSource 中分层添加您想要的任何功能,以确保一切正常工作。有可用于支持工具提示的绑定(bind)。

接下来,我并不是说这是唯一的方法,但我建议将 ArrayController 放回到 xib 中。 NSController 子类和绑定(bind)到它们的控件之间似乎存在一种特殊的关系——绑定(bind)检查器中的 Controller Key: 条目强烈暗示了这一点,因为当您不使用它时它会被禁用。我不确定,但我猜测当您通过那个大 keyPath 绑定(bind)以返回文档以获取 arrayController 时,这种魔法并没有发生。

我还想知道为什么您希望 NSArrayController 位于其控件绑定(bind)的窗口之外的其他位置?相关地,为什么你会让 WindowController 与 Document 共享 NSArrayController ?

NSArrayController 保存选择状态,因此每个窗口都有一个,或者更抽象地说,它们将靠近 UI,因此应该存在于每个需要它的 Nib 中,这确实是有意义的。也就是说,除非您尝试做一些非常规的事情,例如在多个窗口之间共享单个选择状态(即更改窗口 A 中的选择,并且窗口 B 中的相应控件也会更改选择以匹配窗口 A)。我将在下面探讨这个问题,但简而言之,我想不出您想要共享 arrayController 而不是将多个 arrayController 绑定(bind)到相同基础数据的任何其他原因。

如果选择共享是您的目标,我认为您最好做一些事情,例如让文档在每个窗口中 nib 创建的 ArrayController 的选择索引上设置键值观察,并让它们将选择传播到其他窗口的 arrayController。

我把这个编码了;它似乎有效。我从 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

文档 Nib 有一个 SOWindowController 的文件所有者。它有一个绑定(bind)到File's Owner.document.dataModel的NSArrayController,以及一个绑定(bind)到ArrayController.arrangedObjects.attributeName的带有一列的NSTableView。

当我创建新文档时会出现两个窗口,每个窗口显示相同的内容。当我更改其中一个的 tableView 选择时,另一个也会更改。

无论如何,希望这对您有所帮助。

关于cocoa - 将数组 Controller 初始化从 nib 移动到代码会破坏 TableView 绑定(bind),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7760643/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com