Apple Developer Connection
Advanced Search
Member Login Log In | Not a Member? Contact ADC

Developing with Core Data

Core Data, new in Tiger, completes the Cocoa vision for building well-factored applications based on the Model-View-Controller (MVC) pattern by providing a strong, flexible, and powerful data model framework. This vision started with Interface Builder which has long provided a world-class solution for defining the user interface, known as the view in MVC terminology, quickly and easily while eliminating innumerable lines of code in the process. Mac OS X v10.3 Panther built on the vision by providing pre-built controller objects in the form of Cocoa bindings which eliminates the need for much of the glue code between an application's user interface and its data model.

Prior to Tiger, however, the tedious job of creating an application's data model, managing it, and saving it to disk has, for the most part, been left up to the developer to handle. And, since every application has some sort of data model, this was a problem that every developer had to solve independently. Core Data changes the game entirely. Firstly, in the same way that Interface Builder vastly simplifies creating user interfaces, Core Data lets you quickly define your application's data model in a graphic way and easily access it from your code. Secondly, Core Data provides an infrastructure to deal with common functionality such as undo and redo and data persistence, allowing you to get on with the task of building innovation into your application.

Core Data is an object-graph management and persistence framework

The technically correct way to describe Core Data is as an object-graph management and persistence framework. In down-to-earth terms, this means that Core Data organizes the application's model layer into a set of defined in-memory data objects. Core Data tracks changes to these objects and can reverse those changes on demand, such as when a user performs an undo command. Then, when it is time to save changes to your application's data, Core Data takes care of archiving the objects to a persistent store. And, it saves data into regular files that users can manage with the Finder, search with Spotlight, backup to CD, and email to friends, family, and coworkers.

Core Data builds on some of the concepts of enterprise-class database application frameworks, such as the Enterprise Objects Framework in WebObjects. However, make no mistake, Core Data is not an object-relational database access framework. Instead, it uses concepts from the database world to take application data management to a new level. It provides a general-purpose data management solution developed to handle the data model needs of every kind of application, large or small. You can build anything from a contact-management application to a vector-art illustration program on top of it. The sky is the limit. Almost any application that manages data objects can benefit by using Core Data.

This article shows you how Core Data works and introduces you to the essential concepts you'll need to know to get up and running with this new and revolutionary technology. First, we're going to look at the definition of a Core Data data model: The managed object model.

The Managed Object Model

Traditional application data models are defined by hand-coding classes with instance variables and suitable accessor methods. Using the Core Data framework, you create a managed object model that provides an abstract definition of the model objects, known as entities, used by an application. The model, known as an entity-relationship model, is defined using Xcode's Data Model Design tool which provides a rich environment to model entities as well as their relationships. In essence, it's your blueprint for your application's data types and the relationships between them.

Core Data: The Simple Data Model

Entity-relationship modeling is a way to describe data structures that can be mapped to an object-oriented system. Since it comes from the database world, there is some terminology that is associated with it that you may not be familiar with. These terms are:

  • Entities, specific pieces of information in a data model.
  • Attributes, the components of an entity. These are usually simple scalar types, such as int, float, or double; C structures such as char *, NSPoint; or an instance of a primitive class, such as NSString, or NSNumber.
  • Relationships, references that an entity can have to other entities. These relationships can be optional or required as well as one-to-one or one-to-many.
  • Properties, a collective term for attributes and relationships.

For example, an application for managing books in a library would contain a Book entity which has attributes of title and ISBN number, and relationships to other entities, such as a Person entity for the book author and a Collection entity that represents a group of books in the library. The Person entity would, in turn, have attributes of first and last names.

In some ways, these concepts closely mirror those of classes and properties that are used in object-oriented programming. However, entity-relationship modeling is concerned only with modeling data and the relationships between different kinds of data, not behavior.

Entities and Managed Objects

Each entity definition in a managed object model requires the name of the entity and the name of the class used at runtime to represent that entity. By default, the class used is NSManagedObject, but the class may be either NSManagedObject or a subclass thereof. The NSManagedObject class implements the functionality needed to fully integrate into the Core Data framework and can represent any entity. It acts as a dictionary in that any of its attributes and relationships can be set using Key-Value Coding (KVC) as well as observed using Key-Value Observing (KVO). The use of KVC and KVO allows managed objects to be used seamlessly with Cocoa bindings.

You may find that the NSManagedObject class will provide all the functionality you'll need. You only need to provide a subclass if you want to provide custom attributes or behavior for a specific entity.

Managed Object Context and Persistent Stores

The managed object model is the design-time representation of the data model. At run-time, you access the data model through a managed object context object. This object, an instance of the NSManagedObjectContext class, serves as your gateway to the rest of the Core Data stack and mediates between it, your application, and the underlying persistent stores. It is the managed object context that performs validation of data objects to ensure that they obey the constraints of the managed object model. It also handles the undo and redo operations.

Core Data: The Managed Object Context

The managed object context uses another object, the persistent store coordinator. This object, an instance of the NSPersistentStoreCoordinator class, contains the managed object model definition and provides access to the on-disk file representation of the data model.

Core Data: The Persistent Store Coordinator

If you are starting an application project from scratch, Xcode provides two project templates that will give you access to a managed object context, both in regular Cocoa-based applications as well as those that leverage Cocoa's document architecture. In a project created using the Core Data Application template, you can obtain a managed object context with the following message:

[[NSApp delegate] managedObjectContext];

In a project created using the Core Data Document-based Application template, you can obtain a context using the managedObjectContext method of the NSPersistentDocument class.

If you are adding Core Data to an existing application, you'll need to create the managed object context and associated objects yourself. Here's an example of how to do this:

 
NSURL *url = [NSURL fileURLWithPath:@"path/to/file.xml"];

NSArray *bundles = [NSArray arrayWithObject:[NSBundle mainBundle]];
NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:bundles];
NSPersistentStoreCoordinator *coordinator =
   [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
[coordinator addPersistentStoreWithType:NSXMLStoreType configuration:nil URL:url error:&error];
NSManagedObjectContext *managedObjectContext = [[NSManagedObjectContext alloc] init];
[managedObjectContext setPersistentStoreCoordinator: coordinator];

Creating, Fetching, and Updating Managed Objects

Once you have a managed object context, you can create, fetch, and update managed data objects.

Creating and Using Managed Objects

In order to be properly managed, a data object needs to be associated with its managed object context and an entity definition that is part of the managed object model that is being implemented by the context. All of this can be accomplished with a convenience method in the NSEntityDescription class. For example, to create a new book object that represents a Book entity, you could use the following:

NSManagedObject *book = [NSEntityDescription
    insertNewObjectForEntityForName:@"Book" inManagedObjectContext:context];

This method gets the object model for the given context and creates a new managed object based on the Book entity. Once you have created a managed object, you can access and modify the data it contains using Key-Value Coding (KVC) methods. For example, to set the title of a book, you would use the following:

[book setValue:@"Tea Time with Moby" forKey:@"title"];

To get the title of the book later, you would use the following:

[book valueForKey:@"title"];

The use of KVC methods allows Cocoa bindings to easily display and operate on the data contained by managed objects. In fact, it is possible to create many kinds of simple applications with absolutely no code at all by defining a model and then using Interface Builder to define bindings to data in the model.

Undo/Redo Management

To provide undo and redo functionality in a traditional Cocoa application, you have to programmatically record all of the actions that modify data with calls to an undo manager. Core Data eliminates the need to write this code. Instead, each managed object context maintains an undo manager. This undo manager uses Key-Value Observing (KVO) to keep track of modifications to registered objects. When an undo or redo command is performed by the user, the undo manager can restore the state of the context.

Saving Changes

All changes to the objects managed by Core Data happen in memory and are transient until they are committed to disk. To commit changes to the data model to disk, simply send a save: message to the managed object context. This behavior preserves the traditional document semantics that users expect in document-based applications.

Fetching Managed Objects

To work with data already in the managed object context, you use a fetch request, a specification of what kind of data you want to work with. For example, you could ask the context to give you "all books" or "any book written by a particular author ordered by last name, highest to lowest".

A fetch request has three parts:

  • The name of the entity that returned objects conform to;
  • An optional predicate that specifies the attributes and relationships the returned objects must or must not have;
  • An optional array of sort descriptor objects that will order the returned objects.

Fetch request templates can be created as part of your managed object model using the Xcode Data Model design tool. This tool lets you create fetch requests and predicates easily. A fetch request created as part of the managed object model can be fetched from the managed object model and then used against the managed object context with the following code:

NSFetchRequest fetchRequest = [model fetchRequestFromTemplateWithName:@"fetchBooks"];
NSArray *books = [context executeFetchRequest:fetchRequest error:&error];

Deleting Managed Objects

An important operation on any data model is the deletion of objects from the model. To delete an object from a managed object context, you would use the following code:

[context deleteObject:managedObject];

Object deletions are made in memory and are not committed until the context is saved to disk.

Prototype UI Generation

Core Data: The Managed Object Context

We've mentioned that you can use Cocoa bindings to connect a Core Data managed object context to your application's user interface. However, early in an application's development life cycle when you are exploring what kinds of objects you need to capture in the data model, you can take advantage of a new feature of Interface Builder that will create prototype interfaces for you. All you need to do is Option-drag an entity from the Xcode Data Model design tool onto a window in Interface Builder and a comprehensive interface will be created for you.

To be sure, this interface probably doesn't match what you want to expose to users when your application is finished, but it is a powerful way to explore the functionality of your data model during development.

Data Formats

In Tiger, Core Data support three different kinds of data store formats to save managed objects contexts to. These formats are:

  • XML file format
  • Binary archive file format
  • SQLite database file format

Each of these formats has its strengths and weaknesses. The XML format is a good testing format as it is fairly human readable. The binary format is not human readable, but provides better performance than the XML format. Both of these formats are atomic—in other words, the entire data model is read from disk and saved to disk in a single operation.

The last format, the SQLite format, is the most scalable and fastest. SQLite is an open source embedded database that is included in Tiger and has many properties which make it an ideal data storage layer for Core Data. It allows Core Data to efficiently optimize the objects that are loaded into memory and leave unused data on disk. This can drastically reduce the memory footprint of your application when working with large data sets.

An important thing to note about all of these formats: Core Data may change the way that it uses them at any time. While it is easy enough to look under the covers and see what is going on with the XML and SQLite data formats, you should never modify the data in these files yourself.

Using Your Own Data Format

If you already have an existing application format, you can still use Core Data with it. You will need to read in your file and create a Core Data object graph. Then, you can exploit all of the advantages of Core Data, such as the automatic undo/redo support.

Conclusion

As you can see, Core Data allows Cocoa to change the game, again. Its world-class solution for application user interface development is now joined by a world-class solution for managing data and connecting the two. The result is an environment which, more than ever, is set up to let you get on with the important business of building your applications.

How You Can Get Started

Getting started couldn't be easier. The first thing you should do, if you haven't already, is to become an Apple Developer Connection member. A free ADC Online membership provides access to the latest Xcode updates and other developer tools. An ADC Select Membership goes further by providing shipping versions of Mac OS X Tiger and Xcode 2 on disc, along with download access to Mac OS X Tiger Server. Select membership also includes direct, one-on-one consultation with Tiger support engineers, a discount on hardware through the ADC Hardware Purchase Program, and ongoing access to pre-release software.

Next, you'll want to set yourself up with the Xcode 2.2 developer tools. It ships as part of each and every copy of Mac OS X Tiger on the Install DVD. Just double-click on the Xcode 2.2 package on the DVD and the developer tools—as well as a set of example code projects and comprehensive documentation in the ADC Reference Library—will be installed on your system. The documentation and sample code will help you learn more about the technologies covered in this article.

For More Information

Updated: 2006-03-06