Cocoa 如何使用核心数据和抽象实体创建主-细节界面?

Cocoa 如何使用核心数据和抽象实体创建主-细节界面?,cocoa,cocoa-bindings,nsarraycontroller,master-detail,Cocoa,Cocoa Bindings,Nsarraycontroller,Master Detail,苹果有一个很好的小教程来制作一个简单的主细节界面。Interface Builder甚至会从核心数据实体自动为您生成一个。然而,我正在尝试做一些比这个简单的例子更复杂的事情,我已经努力了一段时间让它工作 我有一个基于核心数据文档的应用程序。该模型包括一个抽象实体页面和页面的几个具体子实体。所有页面都有一些共同的属性(如“名称”),这些属性在页面中定义。显然,子实体具有其独有的属性 我希望该界面允许用户查看主列表(NSTableView)中所有类型的页面。当他们选择一个页面时,显示的详细信息字段将

苹果有一个很好的小教程来制作一个简单的主细节界面。Interface Builder甚至会从核心数据实体自动为您生成一个。然而,我正在尝试做一些比这个简单的例子更复杂的事情,我已经努力了一段时间让它工作

我有一个基于核心数据文档的应用程序。该模型包括一个抽象实体页面和页面的几个具体子实体。所有页面都有一些共同的属性(如“名称”),这些属性在页面中定义。显然,子实体具有其独有的属性

我希望该界面允许用户查看主列表(NSTableView)中所有类型的页面。当他们选择一个页面时,显示的详细信息字段将取决于该页面的类型

以下是我现在拥有的:

我有一个主nib文件,其中显示主列表,以及一个页面共有的所有字段。每个页面类型都有一个nib及其特定字段。主nib文件中有一个主NSArrayController,它正在填充NSTableView。每个页面特定的NIB中都有一个NSArrayController,这样我就可以将细节字段绑定到当前选择的属性。我所有的NSArrayController都配置相同,并且我将它们都绑定到相同的managedObjectContext和相同的SelectionIndex

我正在使用Aaron Hillegass在其Cocoa书中描述的视图交换方法。因此,我注册了NSTableViewSelectionDidChangeNotifications,当我收到一个通知时,它会调用一个方法switchView:

switchView查看当前选定的对象,检查它是哪种类型的页面,并根据Hillegass的方法交换相应的nib文件

如果只添加一种类型的页面,一切正常,但一旦添加第二种类型的页面,就会出现以下错误:

为对象的键路径选择索引设置值时出错(来自绑定对象实体:页,所选对象数:1):[valueForUndefinedKey:]:实体NoColPage不符合键端的键值编码

错误的最后一部分是有意义的:它试图显示错误的nib,因此它试图绑定到该对象不存在的字段

我在我的文档中添加了一个SelectionIndex字段,这样我的所有NSArrayController都可以绑定到同一个位置。我为这件事苦恼了好几天,但我想不出来。有什么想法吗

如果有帮助的话。我从我的项目中只提取了与此问题相关的内容,并将其放入一个新的虚拟应用程序中,我一直在使用它进行测试和处理

PS:Interface Builder的从核心数据实体生成主细节接口的工具不像我希望的抽象实体那样工作。它仅为SuperEntity中的属性创建字段

Edit:我想约书亚知道了一些事情,但不幸的是,它不起作用——我一直遇到同样的问题。起初我很难理解-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];
}

}

问题是您将NIB的数组控制器绑定到文档的选择,这导致它们尝试(当选择更改时)表示所选项目

试试这个:

  • 移除NIB中的绑定
  • 在添加新视图之前,请在代码中连接其绑定
  • 删除旧视图之前,请在代码中断开其绑定

  • 这应该能让一切都开心。

    在花了太多时间试图让每个NIB的阵列控制器同步后,我放弃了这种方法。对我来说唯一有效的方法就是通过编程控制在主nib中显示哪些GUI元素及其绑定。这意味着消除其他笔尖。如果您处理的不仅仅是几个文本字段,那么这并不是一个可持续的解决方案,但它现在对我很有效


    我仍然遵循Joshua的建议,在切换视图之前解除绑定,但现在我只将文本字段绑定到arrayController.selection.whateverKey

    这实际上与核心数据无关-暂时删除该标记。谢谢!我想你知道了一些事情,但它仍然在做同样的事情。我在原来的问题帖中添加了更多的信息。你从哪里/如何得到类名?这很重要。你有没有仔细检查过这段代码,看看它是否真的像预期的那样运行?类名不是问题所在,是的,我已经检查过了,一切都像预期的那样运行。但它仍然拒绝工作。我能找到的唯一解决方案是以编程方式控制主NIB中显示哪些GUI元素(从而消除多个NIB)。这并不漂亮,但现在必须这样做。