Coredata – the iPhone way!

Coredata debuted with Mac OS 10.4 Tiger and was brought to iPhone with v3.0. Keeping it simple, Coredata is a schema driven object persistence framework that serializes and deserializes objects to a data store … bla bla bla!

Now the real definition: Coredata is a framework that acts as an object layer between database and your model classes (model classes represent data, in a recipe app, recipes represent data). You keep only the required model (entity) objects in the memory as a collection of objects (called object graph), coredata takes care of storing and retrieving objects based on your requests for objects. Another way to describe coredata is by stating that it is an object to relational mapping framework. In your program you deal with objects and their relationships, framework stores these objects (entities) in a relational data store (with some exceptions) transparently.

Before we dive further, lets try to get a handle on some terms and terminology related to Coredata.

Store: the data file (could be a SQLite database or another data source)
Data model: data schema that is used to create objects at runtime and also the structure of data store
Managed Objects: data objects (model classes in your application)
Managed Object Context: Object graph (Collection of objects that are related to each other thru some relationship – generally represented by a tree and relationships between tree nodes – if you care to know)

Object to relational mapping

Lifecycle of Coredata engine (I am calling it engine because once you use coredata in your application, its a running instance of the framework), like any other process can be broken down into three different phases:

Phase 1: Coredata Engine setup
Phase 2: Interacting with the engine
Phase 3: Tear down

Phase 1: The Engine setup
In this phase, you will setup the coredata.framework in your app, create your schema, point it to coredata engine, establish a data store (SQLite is a store) and get ready for your first get/set data request (but obvious, engine needs to be up and running before you can ask it to save or retrieve data for you). In other words, we need to undertake all these steps before coredata engine will start serializing data (automatically) and fetching managed objects for us.

Please note that Coredata is not a concept for beginners, you need to understand MVC and some iPhone related design patterns (like delegates) to make some sense out of this.

The engine setup phase can be broken down in 4 simple steps:

Step 1: Load the “Model” (Here model refers to the schema that you create using XCode data modeler)
Step 2: Create the “Store Coordinator” and set the “Model” (Store coordinator manages the stores – for e.g. SQLite db)
Step 3: Add store to the Coordinator
Step 4: Create the “Context” and set the “Coordinator”

Lets assume that Store Coordinator is the engine. It is tasked with managing single or multiple stores (remember Coredata supports three store types – Binary, SQLite, XML – XML is not supported on iPhone) A Graphical representation of the store would not be out of place.

Store Coordinator is the Engine!

Once these four steps are accomplished successfully, you are ready to persist and fetch managed objects. Let me request you to pause and think about the statement I made in the previous paragraph. Store Coordinator can manage three types of stores: Binary, SQLite and XML. XML is not supported for iPhone (Don’t forget Mac OS also uses Coredata), so that leaves two store types: Binary and SQLite. This is where a lot of iPhone developers limit their architectural thought process – by thinking that Coredata is all about an object layer on SQLite. Though you will use Coredata with SQLite most of the times but spend sometime learning the binary approach, it may be useful with blobs and streams.

Back to the steps in detail:

Step 1: Load the model

Lets assume that you are using Coredata for the first time. You have read a bit about coredata and decided to get rid of your database code. So the question is: Where do I start? You start with creating a new project in XCode, select a NavigationController based or a Windows based project and it will add coredata.framework to your project. XCode gives you an option to enable a checkbox for enabling Coredata support.

Note the check box for Coredata support

Of course, this does not mean that we have loaded the model, I showed this step as it is a crucial preliminary step to get coredata going in your application. You can also add the coredata.framework to your project manually you don’t need to though. Complicating development steps does not make you a better programmer by any means. If you’ve got a powerful IDE, use it for the gut work. (personally I find it funny when developers take pride in doing things manually that IDE can do for them, its like: Do you know how to (re)invent a wheel? I do, but I prefer PIRELLI for my car).

This step (Loading the model) assumes that you have already used XCode to create a data model(s) for your application. If not, go to “New File …” –> “Resources” — “data model” to create one and add it to your project in “Resource” directory.

In code loading the model is three line code: You simply tell the NSManagedObjectModel class what, where and how to pick up the data model from.

– (NSManagedObjectModel *)managedObjectModel {

if (managedObjectModel != nil) {
return managedObjectModel; }

// This is where you are loading the model
managedObjectModel = [[NSManagedObjectModel mergedModelfromBundles:nil] retain];
return managedObjectModel; }

Step 2 and 3: Create the Store Coordinator and assign the ManagedObjectModel and Data Store to it

Now that you have created the schema and requested ManagedObjectModel class to use that schema as its data model (in step 1), the next step is to attach this newly created managedObjectModel (and data store) to the Store Coordinator. Obviously, we will need to create the Store Coordinator before we do that. So lets get to it.

Remember in step 1, we automatically picked up the schema (data model, the *.xcdatamodel file) and created a Managed Object Model from it but the physical store (SQLite db) still needs to be associated with the Store coordinator. Again, its a three way trust: Store coordinator, The managed Object Model and the Store (SQLite DB) itself. Store Coordinator is tasked with managing this trust relationship.

– (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

if (persistentStoreCoordinator !=nil) { return persistentStoreCoordinator; }

// This is where we construct the URL for our physical store – SQLite DB. Later we will provide this URL to Store Coordinator to   //point to the physical store

NSURL *storeURL = [NSURL fileURLWithPath: [[ self applicationDocumentsDirectory]
stringByAppendingPathComponent : @”Recipe.sqlite“]];

NSError *error;

// This is where you create and initialize the store coordinator
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];

if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreTypeconfiguration:nil URL:storeURL options:nil error:&error]) {
// Handle the error here just in case Store is not initialized
}

return persistentStoreCoordinator;

}

Step 4: Create the Context and set the Coordinator (that will manage the context)

Now that we have a schema, Store Coordinator and a physical data store in place, we need to create the engine (or the workshop where managed objects will be kept consistent). ENGINE is a term that I am have introduced in this blog entry to highlight the importance of Store Coordinator and Managed Context. In my mind Store Coordinator and Managed Context put together are the ENGINE. Store Coordinator binds everything together and Managed Context binds all the Managed Objects for a given data model together. Understanding the managed context is very important as it is the Managed Context Object that does all the housekeeping tasks (object lifecycle mgmt, relationships, undo/redo) on managed objects.

– (NSManagedObjectContext *) managedObjectContext {

if (managedObjectContext != nil) {
return managedObjectContext; }

NSPersistentStoreCoordinator *storeCoordinator = [self persistentStoreCoordinator];
if (storeCoordinator != nil) {
managedObjectContext = [[NSManagedObjectContext alloc] init];
[managedObjectContext setPersistentStoreCoordinator: storeCoordinator]; }

return managedObjectContext; }

So finally, your store / data layer is ready to be used. Phase 1 of “Engine setup” is completed. The data store is set, coredata engine is waiting for your application to storage/retrieval and housekeeping requests. Your application has entered Phase 2.

Phase 2: Interacting with the engine

Before we go into using the Coredata stack and how your application code will interact with ManagedContext, it is important to mention something about your schema file, the .xcdatamodel file that you created with XCode data modeler. This file stores your entity types and their relationships. You can use this model to generate your ManagedObject class stubs. By default, this step is not required but if you want to create your managed object stubs (class files) you can do that.

Assuming all your managed objects are defined, data model, context and store coordinator are set, you are ready to start interacting with the coredata stack (I prefer to call it the engine).

In your application, the reason your entity/model classes are called Managed Objects is (if they are managed by coredata stack) because they are managed by ManagedOjectContext. ManagedObjectContext performs all housekeeping operations on your managed objects. A good way to describe ManagedObjectContext and its relationship with Managed Objects is by stating that: If Managed Objects (entities/model classes) are NOUNS, ManagedObjectContext is the workshop that uses VERBS (actions like fetch, delete, insert, save and observe changes) to perform actions on managed objects. All you do is update the state of the object or request an object (like any other objective C object by calling getter or setter method), ManagedObjectContext does the rest. Cool hmm! … (under the hood, an object graph that manages objects optimally).

Lets say you have a Recipe table and Category table. Each Category has multiple recipes. Both these tables are part of the ManagedObjectContext, and you want to insert a new Recipe, all you do is create a recipe object (make sure you set its context) and set its category by using, let’s say, setCategory() setter method. ManagedObjectContext takes care of the rest.

Coredata stack (engine) is so powerful that it can perform cascading deletes for you. Lets say 10 recipes are related to a category called “Chicken” and you delete the category “Chicken”, ManagedObjectContext will take care of deleting all the recipes that belong to “Chicken” category for you. Isn’t it neat?

Fetching data is equally clean. There is a class called NSFetchRequest which does the task of fetching ManagedObjects from a data store. You can equate it with a SQL Query. All you need to provide are three parameters.

– Entity Name
– Filter Predicate (“Like” search criteria; all records like “Chick”)
– Sort Order

The diagram below shows a good representation of a Fetch request:

Fetch request / response flow

To learn more about the NSFetchRequest, read iPhone Docs here.

Though the optimizations around data retrieval can be a huge topic in itself but still let me touch upon how you can take advantage of Coredata stack to optimize your fetch requests and thereby use memory effectively. The most important architectural imperative to keep in mind while fetching data is that each ManagedObject represents a tuple on your table (apart from transient properties) and hence the choice of bringing all properties (columns) or some properties in memory is entirely up to you. NSFetchRequest has a provision for fetching some properties using setPropertiesToFetch. Another architectural imperative that is directly related to performance is prefetching of related data sets. One such example is: setRelationshipKeyPathsForPrefetching, another example is: setBatchSize where you can set the batch size of data set to be brought into memory.

Similarly deleting managed objects is as simple as calling deleteObject method on ManagedObjectContext.

Some comments about “Faulting and Uniquing” before we step into the tear down phase. Faulting, along with Uniquing is a mechanism for Coredata Engine (stack) to optimize memory. A fault is a representation of an unrealized managed object. This means that a placeholder managed object represents the real object in memory but the properties (columns) have not been brought into the memory. The managed object is realized (completely brought in memory) when the fault is realized. Similarly Uniquing allows a common child object to be brought only once in the memory. Lets say a recipe belongs to two or more categories, the recipe, will be brought in the memory only once.

Saving requires a bit of attention. When ManagedObjectContext gets data from a data store, it pretty much gets the snapshot of the data. This means, if you have multiple ManagedObjectContext objects accessing the same data source, it can result in conflicts. Snapshots participate in OPTIMISTIC LOCKING. When framework saves, it compares the values in each edited object’s snapshot and the current object values in the store. If the values are the same, then it proceeds normally and stores the data. If the values are different then this is an example of OPTIMISTIC LOCKING FAILURE. Default behavior is for the save operation to fail as per NSErrorMergePolicy that brings the @conflict list as return value. To learn more about policies, click here.

Phase 3: Tear down

Tear down is as simple as saving the state of objects releasing coredata stack related objects like any other Objective-C objects.

Per Apple Coredata team, this is how performance numbers on Coredata look:

80% improvement in performance with batching (setBatchSize:)

Advertisements

3 thoughts on “Coredata – the iPhone way!

  1. sathish says:

    usually serialization process stores state of object in files. coredata stores as relational model like rows and columns. Each row acts as a object and it’s like array of objects.

  2. Ravi Joshi says:

    The MVC architecture is preferred for developing application as this allows isolation of the Controller Logic(application logic) from the UI logic (view logic) and thus enable independent testing and development of each of them. This is how Apple develops its application based on the MVC architecture: Model(Core Data)-View(Interface Builder)-Controller(CoCoa). The Core data framework takes care of storing and retrieving objects based on the Create and Fetch Requests from the Controller objects.
    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

  3. Venkatesh S.R says:

    The Architecture is responsible for developing the application. Object relational mapping framework coredata is used store and retrieve objects based. The object to relation mapping establishes, The Knowledge of MVC architecture is preferred for developing application. Store Coordinator will manage the stores. The core data going in to the application. Fetch the data and operate with the managed objects. sort by using the given name.

    core data follows the store formats to save managed objects they are xml file format, binary archive file format, SQLite database file format.

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