Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 如何防止对NSOutlineView的父节点进行排序?_Objective C_Macos_Cocoa_Nsoutlineview - Fatal编程技术网

Objective c 如何防止对NSOutlineView的父节点进行排序?

Objective c 如何防止对NSOutlineView的父节点进行排序?,objective-c,macos,cocoa,nsoutlineview,Objective C,Macos,Cocoa,Nsoutlineview,我不想对NSOultineView的父节点进行排序 我的大纲视图的数据源是一个NSTreeController 单击列标题时,我只希望从层次结构的第二级对树及其子节点进行排序,并使父节点保持相同的顺序 更新 这就是我如何将列绑定到值并分配排序描述符的方法 [newColumn bind:@"value" toObject:currentItemsArrayController withKeyPath:[NSString stringWithFormat:@"arrangedObjects

我不想对NSOultineView的父节点进行排序

我的大纲视图的数据源是一个NSTreeController

单击列标题时,我只希望从层次结构的第二级对树及其子节点进行排序,并使父节点保持相同的顺序

更新 这就是我如何将列绑定到值并分配排序描述符的方法

    [newColumn bind:@"value" toObject:currentItemsArrayController withKeyPath:[NSString stringWithFormat:@"arrangedObjects.%@", metadata.columnBindingKeyPath] options:bindingOptions];
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:metadata.columnSortKeyPath ascending:YES selector:metadata.columnSortSelector];
    [newColumn setSortDescriptorPrototype:sortDescriptor];

您可以使用自定义比较器

为了演示此方法的基本思想,假设您使用
NSTreeNode
作为树节点类。所有根节点都存储在名为
content
NSArray
中,三个根节点分别是
cat
dog
fish

NSTreeNode *cat = [NSTreeNode treeNodeWithRepresentedObject:@"cat"];
// ...the same for dog and fish
self.content = @[cat, dog, fish];
然后,创建您的
NSSortDescriptor
原型。请注意,您应该使用
self
作为键,而不是正在比较的字符串(在本例中为
representedObject
)来访问原始节点对象。在比较器中,检查对象是否包含在根对象数组中。如果
YES
,只需返回
sensorderedname
,因为它将保持
内容
数组中的初始顺序不变,否则使用
比较:
方法进行标准比较

NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"self" ascending:YES comparator:^NSComparisonResult(NSTreeNode *obj1, NSTreeNode *obj2) {

    if ([self.content containsObject:obj1] && [self.content containsObject:obj2]) {
        return NSOrderedSame;
    }

    return [obj1.representedObject compare:obj2.representedObject];
}];

[[outlineView.tableColumns firstObject] setSortDescriptorPrototype:sortDescriptor];

编辑2

如果有多个列需要单独排序,则不能使用
self
作为每一列的键,因为该键在所有列的
sortDescriptorPrototype
s中应该是唯一的。在这种情况下,您可以创建一个自定义对象作为
representedObject
,并将所有数据(包括指向对象中树节点的指针)包装回去

编辑1

上述方法的正确性要求
NSOutlineView
使用稳定的排序算法对其行进行排序。也就是说,相同的项目在排序前后始终保持相同的相对顺序。然而,我在苹果的文档中找不到任何关于这里使用的排序算法稳定性的证据,尽管根据我的经验,上述方法实际上是可行的

如果感到不安全,可以根据当前顺序是升序还是降序显式比较根树节点。为此,您需要一个
ivar
来保存当前订单。只需实现
outlineView:sortDescriptorsDidChange:
delegate方法:

- (BOOL)outlineView:(NSOutlineView *)outlineView sortDescriptorsDidChange:(NSArray *)oldDescriptors {
    ascending = ![oldDescriptors.firstObject ascending];
    return YES;
}
并将
返回指定名称
更改为:

if ([self.content containsObject:obj1] && [self.content containsObject:obj2]) {
    NSUInteger index1 = [self.content indexOfObject:obj1];
    NSUInteger index2 = [self.content indexOfObject:obj2];
    if (ascending)
        return (index1 < index2) ? NSOrderedAscending : NSOrderedDescending;
    else
        return (index1 < index2) ? NSOrderedDescending : NSOrderedAscending;
}
这样,当用户单击标题时,您也可以得到通知。之后,作为KVO流程的一部分,不要忘记实施以下观察方法:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if ([keyPath isEqualToString:@"sortDescriptors"]) {
        // Again, as a simple demonstration, the following line of code only deals with the first sort descriptor. You should modify it to suit your need.
        ascending = [[change[NSKeyValueChangeNewKey] firstObject] ascending];
    }
}

为了防止内存泄漏,您必须在解除分配
outlineView
之前(如果不是更早的话)删除此观察者。如果您不熟悉KVO,请务必检查。

您是否尝试设置您单击的NSTableColumn实例的自定义
sortDescriptorPrototype
?@Astoria是!我已经尝试过了,它对该列有效(使用来自父节点的数据)。但是子节点在其他列中有数据,应该可以通过单击此类列标题对子节点进行排序。但是,当单击这两列时,父节点顺序也会受到影响。请尝试为这两列设置
sortDescriptorPrototype
。@Astoria否此方法无效。我有40个专栏。这些子项具有所有这些列的字段。而且它们必须是可排序的(为孩子们)。如果我只是删除排序,那么孩子们就不能再排序了。嘿,谢谢你,回答得很好。我刚刚阅读了您的编辑:不幸的是,我不能使用outlineView:sortDescriptorsDidChange:因为我没有使用数据源方法(而是以编程方式绑定值)。因此,如果我添加一个数据源,我必须覆盖所有必需的方法。(相反,我仍在研究比较器方法,请尽快回来)。@Patrick如果您无法实现
outlineView:sortDescriptorsDidChange:
,您可以手动将观察者附加到
outlineView
sortDescriptors
数组:
[outlineView addObserver:self forKeyPath:@“sortDescriptors”选项:NSKeyValueObservingOptionNew context:nil]通过这种方式,当用户单击标题时,您也可以收到通知。是的,很酷。我现在使用的是观察者:但是,我如何在这一点上引入比较函数呢?请看我问题中的更新,我已经添加了代码。我有许多自定义列,我正在为它们绑定并设置不同的排序描述符。您必须确保所有列的排序描述符的键都不同,并且您可以通过使用的键路径访问根节点对象。请参阅我的更新。在我的回答中,我使用了一个比较器,它是一个块。如果您更喜欢自定义排序选择器,那就好了,因为它的工作原理与块几乎相同,只是您必须在比较对象的类中实现排序选择器。
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if ([keyPath isEqualToString:@"sortDescriptors"]) {
        // Again, as a simple demonstration, the following line of code only deals with the first sort descriptor. You should modify it to suit your need.
        ascending = [[change[NSKeyValueChangeNewKey] firstObject] ascending];
    }
}