如何将 NSTreeController、NSOutlineView 和 Core Data 与“不可见”的根项一起使用?

Posted

技术标签:

【中文标题】如何将 NSTreeController、NSOutlineView 和 Core Data 与“不可见”的根项一起使用?【英文标题】:How do I use NSTreeController, NSOutlineView and Core Data with an "invisible" root item? 【发布时间】:2009-11-05 06:06:10 【问题描述】:

我有一个核心数据模型,它由一个特定实体的简单树组成,它有两个关系,parentchildren。我有一个 NSTreeController 管理模型,NSOutlineView 绑定到 NSTreeController

我的问题是我需要一个根对象,但这不应该显示在大纲视图中,只有它的子对象应该显示在大纲视图的顶层。如果我在 Interface Builder 中将 NSTreeController 的 fetch 谓词设置为 parent == nil,则一切正常,除了根项目在大纲视图中作为***项目可见。

我的实体有一个属性,isRootItem,仅适用于根项。

我的模型如下所示:

Node 1
|
+-Node 2
  |   |
  |   +-Node 5
  |
  Node 3
  |
  Node 4

大纲视图应如下所示:

(来源:menumachine.com)

我需要在大纲视图的顶层显示节点 2、3 和 4(节点 1 不应该是可见的),但它们的父节点仍然是“节点 1”。节点 1 对于 isRootItem 的值为 YES,所有其他节点的值为 NO

如果我将树控制器的获取谓词设置为parent.isRootItem == 1,这将正确显示树,但是一旦我将新项目添加到顶层它就会失败,因为树控制器没有分配“不可见”根项作为新项的父项。

有没有办法让NSTreeController/NSOutlineView 组合在这种情况下工作?

【问题讨论】:

您可以将谓词简单地写为parent.isRootItem 而无需检查。 【参考方案1】:

我最终做的是继承 NSTreeController 并覆盖 -insertObject:atArrangedObjectIndexPath: 以直接将父对象设置为我的根对象,如果正在插入的对象被插入到树的顶层。这似乎工作可靠。

显然需要更多的工作来处理移动项目和插入多个项目,但这似乎是最好的方法。

- (void)insertObject:(id)object atArrangedObjectIndexPath:(NSIndexPath *)indexPath

    NodeObject* item = (NodeObject*)object;
    //only add the parent if this item is at the top level of the tree in the outline view
    if([indexPath length] == 1)
    
        //fetch the root item
        NSEntityDescription* entity = [NSEntityDescription entityForName:@"NodeObject" inManagedObjectContext:[self managedObjectContext]];
        NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init]; //I'm using GC so this is not a leak
        [fetchRequest setEntity:entity];
        NSPredicate* predicate = [NSPredicate predicateWithFormat:@"isRootItem == 1"];
        [fetchRequest setPredicate:predicate];

        NSError* error;
        NSArray* managedObjects = [[self managedObjectContext] executeFetchRequest:fetchRequest error:&error];

        if(!managedObjects)
        
            [NSException raise:@"MyException" format:@"Error occurred during fetch: %@",error];
        

        NodeObject* rootItem = nil;
        if([managedObjects count])
        
            rootItem = [managedObjects objectAtIndex:0];
        
        //set the item's parent to be the root item
        item.parent = rootItem;
    
    [super insertObject:object atArrangedObjectIndexPath:indexPath];
    //this method just sorts the child objects in the tree so they maintain their order
    [self updateSortOrderOfModelObjects];

【讨论】:

【参考方案2】:

您是否尝试过绑定到 NSTreeController 的 addChild: 方法?

正因为如此,我才不使用 NSTreeController。

您可以取消它并实现 Source 视图的委托方法,这将使您更好地控制显示的内容。这不是太多额外的工作,并且可能比试图让 NSTreeController 以你想要的方式工作更容易。

【讨论】:

这适用于创建现有节点的子节点。例如,如果我选择“节点 2”并调用 -addChild:,那么将正确创建一个子节点。但是,我不能做的是创建与节点 2 相同级别的新节点。如果我调用“-add:”,则会创建一个新节点,但它的父节点是 nil,而不是我的根项目“节点 1”。 如果我不能让 NSTreeController 按我需要的方式工作,那么我肯定会恢复到 NSOutlineView 的数据源/委托方法,但是 NSTreeController 非常接近工作,我想尝试一下路径优先。 看看你得到的其他答案会很有趣。我知道你所说的 NSTreeController 是什么意思——有时感觉它就快到了……

以上是关于如何将 NSTreeController、NSOutlineView 和 Core Data 与“不可见”的根项一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

给定模型对象,如何在 NSTreeController 中找到索引路径?

将 NSTreeController 与 MagicalRecord 绑定

具有两个不同核心数据 NSManagedObject 实体的 NSTreeController

从 NSTreeController 中删除具有特定标题的对象

检索所有 NSTreeController 的对象

NSTreeController/NSOutlineView 失去选择