gpt4 book ai didi

objective-c - 过滤 NSOutlineView 的内容

转载 作者:行者123 更新时间:2023-12-03 16:40:53 25 4
gpt4 key购买 nike

我已经使用 DataSource 设置了 NSOutlineView

提供给 NSOutlineView 的数据基本上是一个自定义节点树,每个节点(我们称之为 PPDocument)具有 2 个基本属性(还有更多) ,但这是重要的部分):

  • 标签(显示的内容)
  • children(子节点数组)

当我的过滤器字段(实际上是 NSSearchField)更改时,我会在大纲 View 上调用 reloadData

因此,我决定将整个过滤插入数据源,如下所示:

- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(PPDocument*)doc {
if (doc==nil) return [[[[APP documentManager] documentTree] groups] count]; // Root
else
{
if ([[[APP fileOutlineFilter] stringValue] isEqualToString:@""]) // Unfiltered
return [doc noOfChildren];
else
return [doc noOfChildrenFiltered:[[APP fileOutlineFilter] stringValue]];
}
}

- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(PPDocument*)doc {
if (doc == nil) return [[[APP documentManager] documentTree] groups][index]; // Root
else
{
if ([[[APP fileOutlineFilter] stringValue] isEqualToString:@""]) // Unfiltered
return [doc childAtIndex:index];
else
return [doc childAtIndex:index filtered:[[APP fileOutlineFilter] stringValue]];
}
}

以及 3 个主要的“过滤”功能:

- (NSArray*)filteredChildren:(NSString*)filter
{
NSMutableArray* ret = [[NSMutableArray alloc] initWithObjects: nil];

if (([self.label contains:filter]) && ([self.children count]==0)) return @[self];

for (PPDocument* d in _children)
{
NSArray* filtered = [d filteredChildren:filter];

if ([filtered count]>0)
{
PPDocument* newDoc = [d copy];
newDoc.children = [filtered mutableCopy];
[ret addObject:newDoc];
}
}

return ret;
}

- (NSInteger)noOfChildrenFiltered:(NSString*)filter
{
NSArray* filtered = [self filteredChildren:filter];

return [filtered count];
}

- (PPDocument*)childAtIndex:(NSInteger)index filtered:(NSString*)filter {
NSArray* filtered = [self filteredChildren:filter];

return (PPDocument*)(filtered[index]);
}

但是,它似乎无法正常工作(+ isGroupItem: 函数突然开始抛出 EXC_BAD_ACCESS 错误)。

有什么想法吗?您注意到任何明显的错误吗?

最佳答案

您的 -filteredChildren: 方法对我来说似乎不正确。

首先,它永远不应该将自身作为其子级之一返回(无论是否经过过滤)。它似乎也不应该复制子节点。

我认为这应该有效:

- (NSArray*)filteredChildren:(NSString*)filter
{
NSIndexSet* indexes = [_children indexesOfObjectsPassingTest:BOOL ^(PPDocument* child, NSUInteger idx, BOOL *stop){
if (child.children.count)
return [[child filteredChildren:filter] count] > 0;
return [child.label contains:filter];
}];
return [_children objectsAtIndexes:indexes];
}

但是,这种方法的问题在于,您正在为项目的每个查询构建已过滤的子项列表。 NSOutlineView 警告数据源方法将被频繁调用并且必须高效。例如,它询问某个项目的子项数量,然后您构建已过滤子项的数组,这需要构建这些子项的已过滤子项的数组等,以便确定某个子项是否应该存在,因为它具有幸存下来的 child 。然后它会询问其中一个 child 有多少个 child ,您必须重建整个子树。

完成此操作后,我让我的节点类跟踪持久数组中的子级和过滤后的子级。每个节点还必须跟踪当前的过滤器。

一种方法是让它们始终保持同步。对子数组所做的任何更改也需要反射(reflect)在已过滤的子数组中。也就是说,如果您添加一个子项并且它通过了过滤器,则将其添加到相应位置的已过滤子项中。如果删除一个子项,它也需要从已过滤的子项数组中删除。

另一种方法是将过滤后的子数组视为缓存。对子数组的任何修改都会使该缓存失效。每当请求过滤后的子数组时,如果它无效,就会重新计算。

无论哪种方式,当节点检测到其过滤子数组已更改或可能已更改(即缓存已失效)从空变为非空或反之亦然时,它需要通知其父级。这是因为它的空性会影响父级是否将其保留在父级的过滤子级列表中。

在第一种不断维护已过滤子数组的方法中,您需要一种方法来设置过滤器。这应该既更新当前节点的过滤子节点,又将新的过滤器传递给所有子节点。在第二种方法中,最后使用的过滤器是缓存的一部分。当请求过滤的子数组时,您测试过滤器是否已更改。如果有,则相当于缓存已失效,因此您需要重新计算它。

关于objective-c - 过滤 NSOutlineView 的内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25886063/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com