如何使用 Core Data 和抽象实体创建主从接口?

Posted

技术标签:

【中文标题】如何使用 Core Data 和抽象实体创建主从接口?【英文标题】:How can I create a master-detail interface with Core Data and an abstract entity? 【发布时间】:2009-11-28 03:33:02 【问题描述】:

Apple 有一个不错的小教程,用于制作简单的主从界面。 Interface Builder 甚至会自动从 Core Data 实体为您生成一个。但是,我正在尝试做一些比简单示例更复杂的事情,并且我一直在努力让它发挥作用。

我有一个基于 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不符合键侧的键值编码。

错误的最后一部分是有道理的:它在尝试显示错误的 nib 时卡住了,因此它试图绑定到该对象不存在的字段。

我在 MyDocument 中添加了一个 selectionIndexes 字段,以便我所有的 NSArrayControllers 都可以绑定到同一个地方。我为此苦恼了好几天,也想不通。有什么想法吗?

如果有帮助,here is a sample project you can download。我只从我的项目中提取了与这个问题相关的东西到一个新的虚拟应用程序中,我一直在用它来测试和玩耍。

PS:Interface Builder 用于从 Core Data 实体生成主从接口的工具不像我希望的那样用于抽象实体。它只为超实体中的属性创建字段。

编辑:我认为 Joshua 正在做某事,但不幸的是,它不起作用——我一直遇到同样的问题。起初我很难过,因为我不明白 -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];

【问题讨论】:

这实际上与 Core Data 无关 - 暂时删除该标签。 【参考方案1】:

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

试试这个:

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

这应该让一切都开心。

【讨论】:

谢谢!我认为您正在做某事,但它仍在做同样的事情。我在原始问题帖子中添加了更多信息。 您在哪里/如何获得 className?这个很重要。您是否已单步执行此代码以查看其实际行为是否符合预期? className 不是问题,是的,我已经完成了,一切都按预期运行。但它仍然拒绝工作。我能找到的唯一解决方案是以编程方式控制在主 NIB 中显示哪些 GUI 元素(从而消除多个 NIB。)这并不漂亮,但现在必须这样做。【参考方案2】:

在花了太多时间试图让每个 NIB 的阵列控制器同步之后,我已经放弃了这种方法。唯一对我有用的是以编程方式控制在主笔尖中显示哪些 GUI 元素及其绑定。这意味着消除其他笔尖。如果您使用的不仅仅是几个文本字段,这并不是一个真正可持续的解决方案,但它现在对我有用。

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

【讨论】:

以上是关于如何使用 Core Data 和抽象实体创建主从接口?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Core Data 模型中动态创建新实体(表)?

SwiftUI 将 Core Data 实体读入 []

使用 NSDocument 时如何将情节提要视图绑定到 Core Data 实体?

是否可以在约束中包含 Core Data 实体类型?

使用 XCode 8 中 Core Data 生成的类创建对象数组

在运行时动态创建 Core Data 实体