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

 Blog
 
 Archive
 
 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
 

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: 2014-09-16 @684 | Home | Admin | Edit
© Copyright 2003-2014 by M. Uli Kusterer, all rights reserved.