Search code examples
cocoasortingnstableviewcocoa-bindingsnsarraycontroller

How is NSTableView Content Sorted After Array Controller Add?


After adding a managed object in array controller class, the bound table view 'places' it into the correct date sorted order.

However, as the table view is building it's rows, the new object has been placed at the bottom of the array controller's content array using:

Edit: Solution: Don't use the array controller's content. The issue was in:

- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
    ....
    //  originally
    NSManagedObject *ci = [[self.arrayController content] objectAtIndex:row];
    // should be: (note arrangedObjects replacing content)
    NSManagedObject *ci = [self.arrayController.arrangedObjects objectAtIndex:row];
    ....
}

The image below shows an example of the placement. Console output from within -tableView: viewForTableColumn: row: at left (from original code above) and ordering in the table view on right. LHR is the new object (notice date order ascending).

enter image description here

Tried:

  1. Saving the moc right after adding newObject
  2. Calling Array Controller's arrangeObjects method
  3. Attempting to manually setSortDescriptors
  4. Binding the table view's selection index to the array controller (for grins)

This is also messing up the selectedRow even though the row with LHR is selected in the table view right after adding. The only way to correct the array controller's order is to manually sort the column.

How can the array controller's content be in sync with the table view? Even more, why might they not be in the same order?


Solution

  • The array controller "arranges" its content. It does this by calling its -arrangeObjects: method. The default implementation filters the contents using the array controller's filterPredicate and then sorts it using its sortDescriptors. A subclass could override that method to arrange the content differently.

    The arranged contents can be accessed using the arrangedObjects property. This is what corresponds to rows in the table view. So, you should always use this if you're indexing by a table row. For example:

    NSManagedObject *ci = [self.arrayController.arrangedObjects objectAtIndex:row];
    

    The array controller's sortDescriptors may be set via bindings (e.g. if the table view's sortDescriptors binding is bound to the array controller). Depending on how you set up the table view bindings, this may be automatic. For NSCell-based table views, you typically bind the table columns value binding and don't bind the table views bindings. In that case, the table view automatically binds its content, selectionIndexes, and sortDescriptors bindings to the same controller as its columns. For view-based table views, you typically don't bind table columns and have to bind those table view bindings explicitly if you want them bound.

    You can also set the array controller's sortDescriptors programmatically.