CoreData and Ordered Objects
One of the biggest holes in CoreData right now (10.4.6) is that it doesn't have support for keeping objects in a particular order. So, here's a quick hack I implemented to get around this. This is terribly inefficient, but since I'm not going to be able to use CoreData for anything but quickly throwing together helper tools until it does ordered items, I haven't yet looked into better solutions.
The approach I'm using is simple: I'm going to add an integer index attribute to my model controlling the order of the items. Then I'm going to use KVO to watch for changes to my array controller that contains the ordered list of objects, and when this order changes, I'll redo the indexes. Once I have these indexes (which I needn't show anywhere in the UI), I can Fetch CoreData objects in a particular order
So, I first need an outlet that I'll connect to my NSArrayController that manages displaying my list in an NSTableView. I'll call it listController. Then I can do
// Make sure our list is always sorted by index:
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"index"
[listController setSortDescriptors: [NSArray arrayWithObject: sortDescriptor]];
// Make sure we get notified of added items:
[listController addObserver: self
in my windowControllerDidLoadNib: or awakeFromNib: method. The notifications will be sent to the following method:
-(void) observeValueForKeyPath: (NSString *)keyPath ofObject: (id)object
change: (NSDictionary *)change context: (void *)context
if( object == listController )
NSArray* objects = [listController arrangedObjects];
NSEnumerator* enny = [objects objectEnumerator];
NSManagedObject* currList = nil;
int x = 0;
while(( currList = [enny nextObject] ))
[currList setValue: [NSNumber numberWithInt: x++] forKey: @"index"];
Which loops over all objects in the object controller and changes their indexes to match the list order. And voila, we have enforced an order on our items. To get those items in order, create a function like the following:
NSManagedObjectContext *moc = [self managedObjectContext];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName: @"UKList"
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity: entityDescription];
// Set example predicate and sort orderings...
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"index" ascending:YES];
[request setSortDescriptors: [NSArray arrayWithObject:sortDescriptor]];
NSError *error = nil;
NSArray *foundObjects = [moc executeFetchRequest: request error: &error];
if( foundObjects == nil )
NSLog( @"%@", error );
Where you'd obviously replace UKList with whatever you named the entity with the index attribute.
Note that this was written for use in a document-based CoreData project, and I haven't yet tested what happens when inserting items (pretty sure it doesn't work), only when adding items. I could probably just loop over the newly-added items and change their numbers and leave the rest alone.
|Sören Kuklau writes:|
Mind adding a few linebreaks? ;-) (Or overflow:scroll?)
NSEntityDescription * entityDescription = [NSEntityDescription entityForName: @"UKList" inManagedObjectContext: moc];
line is extremely wide , making the entry rather difficult to read.
Just saying. :-)