Uli's Web Site
[ Zathras.de - Uli's Web Site ]
Other Sites: Stories
Abi 2000
Stargate: Resurgence
Lost? Site Map!
     home | blog | moose | programming | articles >> blog

 Blog Topics

15 Most Recent [RSS]

 Less work through Xcode and shell scripts
2011-12-16 @600
 iTunesCantComplain released
2011-10-28 @954
 Dennis Ritchie deceased
2011-10-13 @359
 Thank you, Steve.
2011-10-06 @374
 Cocoa Text System everywhere...
2011-03-27 @788
 Blog migration
2011-01-29 @520
 All you need to know about the Mac keyboard
2010-08-09 @488
 Review: Sherlock
2010-07-31 @978
 Playing with Objective C on Debian
2010-05-08 @456
 Fruit vs. Obst
2010-05-08 @439
 Mixed-language ambiguity
2010-04-15 @994
 Uli's 12:07 AM Law
2010-04-12 @881
 Uli's 1:24 AM Law
2010-04-12 @874
 Uli's 6:28 AM Law
2010-04-12 @869
 Uli's 3:57 PM Law
2010-04-12 @867


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
				forKeyPath: @"arrangedObjects" 
				options: NSKeyValueObservingOptionNew
				context: NULL];
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:
-(NSArray*)		orderedObjects
	NSManagedObjectContext	*moc = [self managedObjectContext];
	NSEntityDescription	*entityDescription = [NSEntityDescription entityForName: @"UKList"
							inManagedObjectContext: moc];
	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]];
	[sortDescriptor release];
	NSError *error = nil;
	NSArray *foundObjects = [moc executeFetchRequest: request error: &error];
	if( foundObjects == nil )
		NSLog( @"%@", error );
		return nil;
	return foundObjects;
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.

Reader Comments: (RSS Feed)
kusterer.blog.comments@chucker.rasdi.net writes:
Especially the NSEntityDescription * entityDescription = [NSEntityDescription entityForName: @"UKList" inManagedObjectContext: moc]; line is extremely wide , making the entry rather difficult to read. Just saying. :-)
Uli Kusterer replies:
Nag, nag, nag! Want, want want! ;-) Is this better? :-)
kusterer.blog.comments@chucker.rasdi.net writes:
Or E-Mail Uli privately.

Created: 2006-05-01 @745 Last change: 2017-09-20 @501 | Home | Admin | Edit
© Copyright 2003-2017 by M. Uli Kusterer, all rights reserved.