23rd Aug 2006

Core Data, Bindings, and Sorting in an NSTableView: The Easy Way

So I’m working on a little Core Data based application that you will hear more about in the future. In it, I have an NSTableView whose coulmn headers are bound to an NSArrayController, which in turn is bound to the managedObjectContext to get all my spiffy data.

Problem #1: Core Data doesn’t do sorting. Every time the app is launched, the data in the table appears randomly. Having it appear sorted on launch was actually really simple. Here’s the solution:

1. Implement a KVC NSArray object in your controller or delegate object, and have it return an NSArray with the default sortDescriptor (here I am sorting by a ‘date’ property):

- (NSArray *)sortDescriptor
{
	if(sortDescriptor == nil){
		sortDescriptor = [NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO]];
		}

	return sortDescriptor;
}

- (void)setSortDescriptor:(NSArray *)newSortDescriptor
{
	sortDescriptor = newSortDescriptor;
}

2. In Interface Builder, bind the sortDescriptors Controller Content Parameter to your controller or delegate object, and set the Model Key Path to whatever you called your NSArray of sort descriptors (in my case, sortDescriptor).

That’s it! It wasn’t as intuitive as I originally thought, but it certainly seems pretty clean to me.

BUT WAIT! We have a new problem now.

Problem #2: Objects that are inserted or changed in the table aren’t sorted properly. Fixing this problem was a little trickier, but I found a solution to it at CocoaDev’s RearrangeObjects page. Here’s my little implementation of it (although original credit should go to JediKnil):

1. Register to hear the NSManagedObjectContextObjectsDidChangeNotification, preferably somewhere in your app controller’s awakeFromNib method.

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(objectsDidChange:) name:NSManagedObjectContextObjectsDidChangeNotification object:[self managedObjectContext]];

2. Next, we implement the objectsDidChange: method:

- (void)objectsDidChange:(NSNotification *)note
{
       [myArrayController rearrangeObjects];
}

This forces the table to check it’s arrangement every time any object is changed, added, or deleted. Depending on your purposes, you may want to use JediKnil’s method which checks for certain properties changes, and avoids rearranging if unneeded.

That’s it! It took me a while to figure this out and I saw others were having the same problems else where and never really got answers, so hopefully this is useful to someone. Good luck!

One Response to “Core Data, Bindings, and Sorting in an NSTableView: The Easy Way”

  1. Mathieu Tozer Says:

    Thanks for poining me here! I have a feeling it will fix not one but two of my app’s annoying problems that you were having as well.

    But is it right to say that you should register your [NSApp delegate] to recieve the NSManagedObjectContextObjectsDidChangeNotification or could it just be the controller object that managed the kind of thing that needs to be updated. Or would registering your application’s delegate ‘fountain outwards’ to all the other objects the notification calling objectsDidChange. To me that seems a bit inefficient.

    Thanks again.

    Can’t wait to see your little app!

    -Mathieu

Leave a Reply