Apple 有一个很好的小教程,用于制作简单的主从界面。Interface Builder 甚至会自动从 Core Data 实体为您生成一个。但是,我正在尝试做一些比简单示例更复杂的事情,并且我一直在努力让它发挥作用。
我有一个基于核心数据文档的应用程序。该模型包括一个抽象实体 Page,以及 Page 的几个具体子实体。所有页面都有一些共同的属性(例如“名称”),并且这些属性在 Page.xml 中定义。显然,子实体具有它们独有的属性。
我希望界面允许用户在主列表(NSTableView)中查看所有类型的页面。当他们选择一个页面时,显示的详细信息字段将取决于它是什么类型的页面。
这是我现在拥有的:
我有一个主 nib 文件,其中显示了主列表,以及页面共有的所有字段。每种页面类型都有一个带有特定字段的 nib。主 nib 文件中有主 NSArrayController,用于填充 NSTableView。每个页面特定的 nib 中都有一个 NSArrayController ,这样我就可以将详细信息字段绑定到当前选择的属性。我所有的 NSArrayController 都配置相同,并且我将它们都绑定到相同的 managedObjectContext 和相同的 selectionIndexes。
我正在使用 Aaron Hillegass 的视图交换方法,他在他的 Cocoa 书中描述了这种方法。于是我注册了NSTableViewSelectionDidChangeNotifications,当我收到一个时,它会调用一个方法switchView:
switchView 查看当前选中的对象,检查它是哪种类型的 Page,并根据 Hillegass 的方法在适当的 nib 文件中交换。
如果我只添加一种类型的页面,一切正常,但是一旦我添加第二种类型的页面,我就会收到此错误:
对象的键路径选择索引值设置错误(来自绑定对象实体:页,选定对象数:1):[ valueForUndefinedKey:]:实体 NoColPage 与键侧的键值编码不兼容。
错误的最后一部分是有道理的:它试图显示错误的笔尖,因此它试图绑定到该对象不存在的字段。
我在 MyDocument 中添加了一个 selectionIndexes 字段,以便我所有的 NSArrayControllers 都可以绑定到同一个地方。我为此苦恼了好几天,也想不通。有任何想法吗?
如果有帮助,这里有一个示例项目,您可以下载。我只从我的项目中提取与这个问题相关的东西到一个新的虚拟应用程序中,我一直在用它来测试和玩耍。
PS:Interface Builder 用于从 Core Data 实体生成主从接口的工具不像我希望的抽象实体那样工作。它只为超实体中的属性创建字段。
编辑:我认为约书亚正在做某事,但不幸的是,它不起作用——我一直遇到同样的问题。起初我很难过,因为我不明白 -unbind: 需要一个字符串常量,而不是一个关键路径。
我尝试了几种变体:我跟踪当前显示的 nib 的阵列控制器;我在其中跟踪当前显示的页面类型,并且仅在尝试显示不同的页面类型时取消绑定/重新绑定...
这是代码的相关部分。
-(void) displayViewController: (ManagingVC *) vc withClass:(NSString*) className {
//Try to end editing
NSWindow *w = [box window];
BOOL ended = [w makeFirstResponder:w];
if (!ended) {
NSBeep();
return;
}
//The Managing View Controller's NSArrayController
NSArrayController* vcAc = [vc arrCont];
//if the page we're trying to switch to is NOT the same type as the current page we're displaying
//if it is, do nothing.
if (![currPageDisplayed isEqual:className]) {
//unbind the old view controller
ManagingVC *oldvc = [viewControllers objectForKey:className];
NSArrayController* oldsac = [oldvc arrCont];
[oldsac unbind:@"selectionIndexes"];
//bind the new view controller
[vcAc bind:@"selectionIndexes" toObject:self withKeyPath:@"selectionIndexes" options:nil];
currPageDisplayed = className;
NSView *v = [vc view];
//display the new view in an NSBox in the main nib
[box setContentView:v];
}
}