Core Data

One of the developer-side enhancements included in iPhone OS 3.0 was Core Data. Core Data is basically an ORM layer, which one could either take or leave; it’s nice to avoid writing all that SQL, but you’re always taking on a lot of baggage by adopting a big ol’ framework like that. It does, however, offer at least one feature that strikes me as really neat: NSFetchedResultsControllers. I explain more below.

Update Messages

The ostensible purpose of NSFetchedResultsController is to “efficiently manage the results returned from a Core Data fetch request to provide data for a UITableView object”. To which I say: “Meh”. The really interesting feature of this class is its delegate property. If you set this property to an object which adopts the NSFetchedResultsControllerDelegate protocol, that delegate will receive messages when changes are made (note: made, not just saved) to the managed object context from which results were fetched.

This is something I would classify as “astoundingly useful”, since it obviates the need for the “triple updating” (of Core Data model, local object model, and view) that otherwise pops up repeatedly in view controllers.

Example

These snippets of code are taken from the iPhone Core Data “Locations” tutorial, after it has been modified (per the suggestion in the tutorial’s “Next Steps” section) to use an NSFetchedResultsController. (Note that I set the controller’s delegate, and added the delegate methods, to the tutorial’s RootViewController class.)

- (void)addEvent
{
	// Get location
	CLLocation* location = [locationManager location];
	if (!location) return;

	// Create and initialize a new instance of the Event entity
	Event* event = (Event*) [NSEntityDescription insertNewObjectForEntityForName:@"Event" inManagedObjectContext:managedObjectContext];
	
	// Configure Event
	CLLocationCoordinate2D coordinate = [location coordinate];
	[event setLatitude:[NSNumber numberWithDouble:coordinate.latitude]];
	[event setLongitude:[NSNumber numberWithDouble:coordinate.longitude]];
	[event setCreationDate:[NSDate date]];

	// Save
	NSError* error;
	if (![managedObjectContext save:&error])
	{
		// Handle the error.
		NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
		exit(-1);
	}
}
- (void)tableView:(UITableView*)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath*)indexPath
{
    if (editingStyle == UITableViewCellEditingStyleDelete)
    {
	// Delete the managed object at the given index path.
        NSManagedObject* eventToDelete = [resultsController objectAtIndexPath:indexPath];
        [managedObjectContext deleteObject:eventToDelete];

	// Commit the change.
        NSError* error;
        if (![managedObjectContext save:&error])
	{
            // Handle the error.
	    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
	    exit(-1);
        }
    }
}
#pragma mark fetched results controller delegate methods

- (void)controllerWillChangeContent:(NSFetchedResultsController*)controller
{
    [self.tableView beginUpdates];
}


- (void)controller:(NSFetchedResultsController*)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath*)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath*)newIndexPath
{
    UITableView* tableView = self.tableView;
    switch (type)
    {
        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
	    [tableView scrollToRowAtIndexPath:newIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
            break;
			
        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}


- (void)controllerDidChangeContent:(NSFetchedResultsController*)controller
{
    [self.tableView endUpdates];
}

As you can see, insertions and deletions now only directly affect the Core Data model; changes to this model trigger updates to the table view through the fetched results controller delegate.

Share and Enjoy:
  • Twitter
  • Facebook
  • Digg
  • Reddit
  • HackerNews
  • del.icio.us
  • Google Bookmarks
  • Slashdot
This entry was posted in iPhone. Bookmark the permalink.