Search code examples
objective-cmacoscocoanstableview

In a NSTableView, how to sort the items based on their selection?


I am developing a macOS Application in Objective-C. I would like to add as a feature the option to sort a NSTableView to show the selected items before the others. My code is:

NSUInteger idx = [self.itemsTableView.selectedRowIndexes firstIndex];

NSMutableArray *selectedObjects = [NSMutableArray new];

while (idx != NSNotFound)
{
    // do work with "idx"
    // NSLog (@"The current index is %lu", (unsigned long)idx);

    [selectedObjects addObject:self.items[idx]];
    // get the next index in the set
    idx = [self.itemsTableView.selectedRowIndexes indexGreaterThanIndex:idx];
}
self.items = [self.unFilteredItems sortedArrayUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {

        BOOL obj1Exists = [selectedObjects containsObject:obj1];
        BOOL obj2Exists = [selectedObjects containsObject:obj2];


        if (obj1Exists && !obj2Exists) {
            return NSOrderedAscending;
        }
        if (obj1Exists && obj2Exists) {
            return NSOrderedSame;
        }
        if (!obj1Exists && !obj2Exists) {
            return NSOrderedSame;
        }
        if (!obj1Exists && obj2Exists) {
            return NSOrderedDescending;
        }

        return NSOrderedSame;

    }];

    [self.itemsTableView reloadData];

Unfortunately, on about 70.000 items and a selection of 4500 items, the comparator takes too much time. Can anybody point to me an alternate solution to the problem ? Thanks for any help.

Edit:

I have now tried another solution which proves to be faster but still not fast enough:

NSUInteger idx = [self.myMessagesTableView.selectedRowIndexes firstIndex];

NSMutableArray *selectedObjects = [NSMutableArray new];

while (idx != NSNotFound)
{
    // do work with "idx"
    // NSLog (@"The current index is %lu", (unsigned long)idx);

    [selectedObjects addObject:self.myMessages[idx]];
    // get the next index in the set
    idx = [self.myMessagesTableView.selectedRowIndexes indexGreaterThanIndex:idx];
}

NSMutableArray *unselectedObjects = [NSMutableArray new];

[self.unFilteredItems enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

    if (![selectedObjects containsObject:obj]) {
        [unselectedObjects addObject:obj];
    }

}];


self.items = selectedObjects;

self.items = [self.items arrayByAddingObjectsFromArray:unselectedObjects];

[self.itemsTableView reloadData];

I hope somebody can point me in the right direction, probably trying to use selection indexes instead of an array of selected objects. Thanks again.


Solution

  • How about getting the selected objects and appending the unselected objects

    NSArray *selectedObjects = [self.items objectsAtIndexes:self.itemsTableView.selectedRowIndexes];
    // invert selectedRowIndexes
    NSMutableIndexSet *invertedSelection = [NSMutableIndexSet indexSetWithIndexesInRange:NSMakeRange(0, self.items.count)];
    [invertedSelection removeIndexes:self.itemsTableView.selectedRowIndexes];
    NSArray *unselectedObjects = [self.items objectsAtIndexes:invertedSelection];
    self.items = [selectedObjects arrayByAddingObjectsFromArray:unselectedObjects];
    self.itemsTableView.selectedRowIndexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, selectedObjects.count)];
    [self.itemsTableView reloadData];
    

    Or removing the selected objects and inserting them at the top

    NSMutableArray *mutableItems = [self.items mutableCopy];
    NSArray *selectedObjects = [self.items objectsAtIndexes:self.itemsTableView.selectedRowIndexes];
    [mutableItems removeObjectsAtIndexes:self.itemsTableView.selectedRowIndexes];
    NSindexSet *selectedIndexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, selectedObjects.count)]
    [mutableItems insertObjects:selectedObjects atIndexes:selectedIndexes];
    self.items = [mutableItems copy];
    self.itemsTableView.selectedRowIndexes = selectedIndexes;
    [self.itemsTableView reloadData];
    

    I didn't test this.