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!
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!
Posted by patrick under
bindings, code, coredata, how-to, sorting
1 Comment »