HOWTO:当列名未知时,使用NSSortDescriptor对每列的TableView进行排序?

时间:2017-04-17 12:12:29

标签: objective-c swift uitableview nssortdescriptor

我正在加载一个我一无所知的CSV文件,除了第一行是列标题,可以是任何内容。列数也是未知的。我尝试在每个列中添加sortDescriptorPrototype,当我这样做时,我会在TableView中看到上/下箭头。

    for(NSTableColumn * col in self.tableView.tableColumns){
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey: col.title ascending: YES];
    col.sortDescriptorPrototype = sortDescriptor;
}

每次单击sortDescriptorsDidChange列时都会调用:

- (void)tableView:(NSTableView *)tableView sortDescriptorsDidChange:(NSArray *)oldDescriptors
    {
        [_data sortUsingDescriptors: [tableView sortDescriptors]];
        [tableView reloadData];
    }

_data是一个NSMutableArray,其中存储数据,第一行是标题名称。每一行都是另一个NSArray不幸的是我收到了这个错误:

2017-04-17 12:35:09.979142+0200 Table Tool[20954:2577488] [General] [<__NSCFString 0x610000474840> valueForUndefinedKey:]: this class is not key value coding-compliant for the key beds.
2017-04-17 12:35:09.982161+0200 Table Tool[20954:2577488] [General] (
    0   CoreFoundation                      0x00007fffb31a837b __exceptionPreprocess + 171
    1   libobjc.A.dylib                     0x00007fffc7f9c48d objc_exception_throw + 48
    2   CoreFoundation                      0x00007fffb31a82c9 -[NSException raise] + 9
    3   Foundation                          0x00007fffb4c83e5e -[NSObject(NSKeyValueCoding) valueForUndefinedKey:] + 226
    4   Foundation                          0x00007fffb4b55d9c -[NSObject(NSKeyValueCoding) valueForKey:] + 283
    5   Foundation                          0x00007fffb4b59aac -[NSArray(NSKeyValueCoding) valueForKey:] + 467
    6   Foundation                          0x00007fffb4b55b79 -[NSArray(NSKeyValueCoding) valueForKeyPath:] + 448
    7   Foundation                          0x00007fffb4b7cc9f _sortedObjectsUsingDescriptors + 371
    8   Foundation                          0x00007fffb4be94f7 -[NSMutableArray(NSKeyValueSorting) sortUsingDescriptors:] + 468
    9   Table Tool                          0x00000001000051d8 -[Document tableView:sortDescriptorsDidChange:] + 184
    10  AppKit                              0x00007fffb0f05425 -[NSTableView setSortDescriptors:] + 260
    11  AppKit                              0x00007fffb13c9fbc -[NSTableView _changeSortDescriptorsForClickOnColumn:] + 480

显然我已经阅读了很多关于这个主题的内容,但是所有的例子都假设您在设计时知道了列名。我对 ObS-C Swift NSSortDescriptor sortUsingDescriptors 的解决方案感兴趣,有些解释在sortDescriptorPrototype上以及为什么首先需要它,因为当我点击列时sortDescriptor会发生变化。我可以使用KVC中的任何东西作为分类键,例如&#34; self&#34; (有... valueForKeyPath:@&#34; @ sum.self&#34; ...)?

一些有用的链接:

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/TableView/SortingTableViews/SortingTableViews.html

https://www.raywenderlich.com/143828/macos-nstableview-tutorial

1 个答案:

答案 0 :(得分:0)

这是一种完全愚蠢的解决方法,部分有效: 首先,我使用此方法提取列索引:

-(NSUInteger)getColumnIndexFromTableViewSortDescriptor {
    for(NSUInteger i = 0; i < _maxColumnNumber; i++){
        if(_tableView.tableColumns[i].title == _tableView.sortDescriptors[0].key){
            return i;
        }
    }
    assert(false && "Missing column name");
    return 0;
}

然后我使用sortUsingComparator对数组进行就地排序。当然这必须是“错误的”。如果不使用sortDescriptors,那么使用sortDescriptors是完全愚蠢的,除了找出点击的列。我猜点击事件也可以解决这个问题吗?

-(void)tableView:(NSTableView *)tableView sortDescriptorsDidChange: (NSArray *)oldDescriptors
{
    NSUInteger idx = self.getColumnIndexFromTableViewSortDescriptor;
    if(tableView.sortDescriptors[0].ascending){
        [_data sortUsingComparator: ^(id obj1, id obj2) {
            return [[obj2 objectAtIndex:idx] compare:[obj1 objectAtIndex:idx]];
        }];
    } else {
        [_data sortUsingComparator: ^(id obj1, id obj2) {
            return [[obj1 objectAtIndex:idx] compare:[obj2 objectAtIndex:idx]];
        }];
    }
    [tableView reloadData];
}

现在我导入列中数据的CSV数据不一致,因此可能是NSNumber,后面跟着三个NSDecimalNumber和一些NSString。部分是我正在使用的数据和/或CSV解析器的问题(从网络上翻录,但我稍后会重写吸盘)。

因此,您最终可能会将NSDecimalNumber与NSString进行比较,这会产生如下错误:

unrecognized selector sent to instance

所以我继续愚蠢:

@interface NSDecimalNumber (CompareString)
-(NSComparisonResult)compare:(NSString *)string;

@end

@implementation NSDecimalNumber (CompareString)

-(NSComparisonResult)compare:(NSString *)string{
    NSString *decimalString = self.stringValue;
    return[decimalString compare:string options:NSCaseInsensitiveSearch];

}

现在,如果比较两个NSDecimalNumber,将调用上面的参数“string”NSDecimalNumber,即使“string”声明为NSString,也会导致“无法识别的选择器再次发送到实例”。