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

 Blog
 
 Blog Topics
 
 Archive
 

15 Most Recent [RSS]

 Review: Sherlock
2010-07-28 @073
 
 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
 
 Uli's 4:41 PM Law
2010-04-12 @864
 
 Uli's 7:25 AM Law
2010-04-12 @862
 
 Uli's 9:36 PM Law
2010-04-12 @861
 
 Typesafe typecasts
2010-04-12 @471
 
 Porting to the Macintosh
2010-04-09 @592
 
 Uli's source code is on Github!
2010-03-05 @986
 
 Downtime on Friday
2010-03-04 @025
 

More...

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"
						ascending:YES];
	[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)
Sören Kuklau writes:
Mind adding a few linebreaks? ;-) (Or overflow:scroll?) 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? :-)
Sören Kuklau writes:
Much better, yes, thanks! :-)
Comment on this article:
Name:
E-Mail: (not shown, hashed for Gravatar)
Web Site URL: (optional)
Comment: (plain text only)
Please Enter the following word:
Or E-Mail Uli privately.

 
Created: 2006-05-01 @745 Last change: 2010-07-29 @713 | Home | Admin | Edit
© Copyright 2003-2010 by M. Uli Kusterer, all rights reserved.