Core Data common coding patterns

In this post, you will learn common coding patterns (CCP) for iOS apps that use Core Data.

.

This post was most recently updated in October 2011.

.

The target audience of this post will be those who are new to Core Data, and probably to iOS programming. This is another way of saying that we will not cover higher-level production or advanced features of Core Data here.

As you know, Core Data is an object design, management, and persistence framework. It is a good choice for any situation where you need to manage and persist model objects. Core Data has classes that offer a range of benefits and productivity for the developer.

.

Common coding patterns for apps that use Core Data

The goal of this post is to show how common operations are done with Core Data. Our starting point is to study a new project – a navigation-based app for the iPhone that uses Core Data. The project template delivers a working app, with no coding changes required to make it “just work”.

Our first task is to highlight the Core Data-related code, provided by the template, that needs little or no changes. Later, we will learn about the common coding patterns in the root view controller.

.

Ready-to-use – app delegate – configuring the Core Data stack

In the app delegate, three Core Data components are configured:

  • Managed object model
  • Persistent store coordinator
  • Managed object context

.

As noted above, the project template delivers a working app. In the app delegate, the awakeFromNib method initializes the root view controller, and causes the initialization of the three components listed above.

The managed object model initializes by processing any “.xdatamodel” files in the app bundle. The persistent store coordinator initializes by using the just-created managed object model, and looking for (or creating) the store file, which is named with the project’s name, and located in the default location. Finally, the managed object context is initialized by using these two just-created objects.

In a typical app, you may not have to make any changes to the code that creates these objects.

Once these three objects are initialized, the managed object context is passed on to the root view controller, by setting a property in the root view controller.

.

Customize  the template-provided code – root view controller

The root view controller that’s created by the project template is a table view controller subclass. Therefore, you would expect that the four typical table view data source and delegate methods would require Core Data related code, and you would be correct.

Additionally, in any UITableViewController subclass, you would expect that the table view’s data source would be either set/provided by a “parent” in a data-bearing property, or initialized when the view controller loads. This continues to be the case. However, the data source gets initialized when the table view begins rendering its user interface.

Now, let’s study the code in the methods, looking specifically at code that involves Core Data objects. There are about six (6) methods that we’ll look at. While we go through the code, remember that the managed object context is already set in a root view controller property.

.

fetchedResultsController (custom property getter) – Deliver the fetched results controller to the caller

Theme(s):

  • Create and configure the fetch request object
  • Execute the fetch, which places the results in the managed object context

.

When the app is launched, the Cocoa runtime begins to render the table view. The first method that gets called is numberOfSectionsInTableView:. It accesses the fetchedResultsController property, which hasn’t yet been initialized in a newly-launched app. Let’s examine this custom property getter first.

The fetch request object is configured first. It needs an entity description, and optionally a predicate, and one or more sort descriptors. In your own app, you will have to write your own code (provide your own implementation).

The project template provides all (or most) of the code you need, so you simply need to modify it to meet your needs.

.

// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:self.managedObjectContext];

// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"timeStamp" ascending:NO];

// Add a predicate as appropriate.

.
Then, the fetched results controller object is created, using the fetch request object, and the managed object context. It is then assigned as the property getter.

Finally, the fetch is executed (which, as noted above, places the results in the managed object context).

.

numberOfSectionsInTableView: (data source method) – Set the number of sections in the table view

Theme(s):

  • Ask the fetched results controller a question about the shape of the data

We do not need to change this code.

.

tableView:numberOfRowsInSection: (data source method) – Set the number of rows in a section

Theme(s):

  • Ask the fetched results controller a question about the shape of the data

We do not need to change this code.

.

tableView:cellForRowAtIndexPath: (data source method) – Configure the cell to add to the table view

Theme(s):

  • Get a managed object from the fetched results controller
  • Open the managed object, and extract an attribute’s value

This method configures the cell with content. The content must come from an attribute in a managed object. Therefore, the first task is to get a reference to the desired managed object. The fetched results controller is an object that’s custom-designed to work with a table view, so all we need to do is ask it for the object at the current table view’s indexPath.

Then, we extract the data that we want to use for the table view cell’s text label, as a string.

In your own app, you will have to write your own code (provide your own implementation). The project template provides all (or most) of the code you need, so you simply need to modify it to meet your needs.

.

// Configure the cell contents
NSManagedObject *managedObject = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = [[managedObject valueForKey:@"timeStamp"] description];

.

tableView:didSelectRowAtIndexPath: (delegate method) – Do work when a table view row gets tapped

Theme(s):

  • Get a managed object from the fetched results controller
  • Pass it on to the next-level view controller

This method does work when a table view row is tapped by a user. Typically, this means that a next-level view controller will be initialized, configured, and presented.

The managed object that backs the tapped row must be obtained (from the fetched results controller), and then passed along to the next-level view controller. Additionally, we will probably want to extract some value(s) from the managed object, so that we can use the value(s) to configure the next-level view controller.

In your own app, you will have to write your own code (provide your own implementation). The project template provides all (or most) of the code you need (although it is commented out), so you simply need to modify it to meet your needs.

.

// Navigation logic may go here -- for example, create and push another view controller.
/*
<DetailViewController> *detailViewController = [[<DetailViewController> alloc] initWithNibName:@"<Nib name>" bundle:nil];
NSManagedObject *selectedObject = [[self fetchedResultsController] objectAtIndexPath:indexPath];
// Configure the detail view controller...
// Set a suitable title for the detail view controller
// (maybe by extracting a value from a managed object attribute)
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
*/

.

(instance method) – Add, edit, or delete a managed object

Theme(s):

  • Add a managed object, or…
  • Get a managed object from the fetched results controller, and edit it

The project template provides an instance method called insertNewObject. You can see that a new managed object is configured with its entity description, and of course, the managed object context. After setting the managed object’s attribute values, you save the context, which persists the new managed object.

Editing an existing managed object is straightforward. Editing is often done in a standard view controller, so your code already has a reference to the managed object. Simply change the attribute values, and save the context.

Deleting an existing managed object is straightforward. Get a reference to the managed object, and call the managed object context’s deleteObject method, with the managed object to be deleted as its argument. The code example below shows two styles.

// Delete the managed object for the given index path
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
[context deleteObject:[self.fetchedResultsController objectAtIndexPath:indexPath]];

// Delete the referringObject, a managed object that you already have a reference to
[[referringObject managedObjectContext] deleteObject:referringObject];

.

Summary

We hope that this post has been useful. By highlighting the Core Data related code for common operations, and showing that it really isn’t complicated, we hope that you will use this framework for almost all of your object management and persistence needs.

.


.

.

.

  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: