如何将 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 【问题描述】:我有一个核心数据模型,它由一个特定实体的简单树组成,它有两个关系,parent
和children
。我有一个 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