Take the 2-minute tour ×

I have an NSTableView which gets populated without bindings.

In the datasource method tableView:objectValueForTableColumn:row:, I re-sort my data and tell the table view to reload after committing the edit to the model, so that the correct sort order is restored after editing.

If the user ends editing by clicking a different row, however, and the sort order has changed because of the edit that has just been ended, it might happen that the row the user intended to select has just moved after he clicked it. So instead of that row, a different row that is now in that spot gets selected.

I tried various combinations of the NSTableViewDelegate methods, but could not find a solution that adjusts the selection in a way that when a re-sort after editing has ended has occurred, the row that has just moved away gets selected. How can I achieve this?

share|improve this question

2 Answers 2

I would use this:

I recommend to sort your data in NSTableView delegate setObjectValue: instead of objectValueForTableColumn:

And change the selection in NSTableView delegate selectionIndexesForProposedSelection:

This solution manages a single selection, If you want it manages single and multiple selection, I would change my answer. If the user double-click, it doesn't work since it changes the selection to the second click.

You need these variables :

int originalRowIndex;
NSUInteger newRowIndex;

I initialize this variable: originalRowIndex = -1;

- (void)tableView:(NSTableView *)aTable setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)aColumn row:(int)rowIndex {
    id objectAtRow = [myMutableArray objectAtIndex:rowIndex];
    NSString *columnKey = [aColumn identifier];
    [objectAtRow setValue:anObject forKey:columnKey];

    originalRowIndex = rowIndex; // get the original index
    [myMutableArray sortUsingDescriptors:[aTable sortDescriptors]]; // re-sort the mutable array
    newRowIndex = [myMutableArray indexOfObjectIdenticalTo:objectAtRow]; // get the new index
    if (newRowIndex == originalRowIndex) originalRowIndex = -1; // same position
// not called on empty selection
- (NSIndexSet *)tableView:(NSTableView *)tableView selectionIndexesForProposedSelection:(NSIndexSet *)proposedSelectionIndexes {
    int oIndex = originalRowIndex;
    originalRowIndex = -1;
    if (oIndex > -1 && [proposedSelectionIndexes count] > 1) { // if oIndex = -1 or multi selection , do nothing
        int i = [proposedSelectionIndexes firstIndex]; 
        if (oIndex < newRowIndex) { 
            if (i > oIndex && i <= newRowIndex) return [NSIndexSet indexSetWithIndex:(i - 1)];//shift the row index
        } else {
            if (i < oIndex && i >= newRowIndex) return [NSIndexSet indexSetWithIndex:(i + 1)];//shift the row index
        } //else doesn't change the selection, this index is out of range (originalIndex...newIndex)
    return proposedSelectionIndexes;// doesn't change the selection
share|improve this answer

I've always done this the hard way: before doing something that needs the selection to be restored, I remember the current selection -- not by row index, but by something I can find in my data. Often I have an array of dictionaries, so I just remember the dictionary pointer.

After doing whatever I need to do on the tableview, I just go through the data again, looking for my object to find the new index...

share|improve this answer
That's exactly what I tried to do, but I didn't succeed. Which datsource/delegate method is the one I need in order to know when to restore the selection? Which one is the right one to save the selection? Or rather the row that is supposed to get selected isn't yet selected until the user clicks it to end editing. –  tajmahal Jul 7 '12 at 23:01

Your Answer


