Core Data is a very powerful framework that Apple provides to developers for persisting data in their applications. The primary advantage that is provided by Core Data is the ability to leverage efficient data storage technologies like SQLite, without forcing the developer to think in terms of query language; Core Data allows a developer to work with the data model in terms of objects.
There are many great books and articles on the proper use of Core Data; including Apple's Core Data Tutorial. The purpose of this article is simply to step the reader through adding the necessary piece to get Core Data into a previously created project; I defer to those other writings to describe the best techniques for Core Data use.
Apple has made the process of using Core Data in new projects very simple. From the New Project... screen, many project templates include a checkbox titled Use Core Data for storage that tells Xcode to build the basics for Core Data into the project you create. But what happens if you decide that Core Data's advantages are going to help you, but you have already have your project set up in Xcode? Where's the button in the IDE to add Core Data to an existing project?
Below is a set of instructions on creating the context necessary to start using ore Data in your existing app. In the code blocks, bold text is code that should already exist in your project.
Add the Missing Files
There are two files that must be added to your Xcode project in order to use Core Data; CoreData.framework and the .xcdatamodel
CoreData.framework
- From Xcode, control-click on the Frameworks folder inside the Groups & Files pane
- Select Add -> Existing Frameworks...
- Locate CoreData.framework, select it, and click the Add button
.xcdatamodel
- From Xcode, control-click on the Resources fold inside the Groups & Files pane
- Select Add -> New File...
- Select Resource from the iPhone OS group
- Select Data Model and click Next
- Give the file a name (the project name is a good choice) and click Next
- If your project does not have existing model classes that you would like to put into the data model, skip to step 7. Otherwise, you may do so by selecting those classes on this screen and clicking Add to place them in the Selected Classes pane.
- Click Finish
Create the Missing Objects
Once all the necessary files are put into the project, the appropriate objects and methods need to be added to the application.
AppDelegate.h
Declare three new objects in the application delegate's header file for the
ManagedObjectModel
, ManagedObjectContext
, and PersistentStoreCoordinator
.
A convenience method, applicationDocumentsDirectory
, is also defined to return
the location of the application's data files:
@interface AppDelegate : NSObject <UIApplicationDelegate> {
NSManagedObjectModel *managedObjectModel;
NSManagedObjectContext *managedObjectContext;
NSPersistentStoreCoordinator *persistentStoreCoordinator;
/* ...Existing Application Code... */
}
@property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;
@property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (NSString *)applicationDocumentsDirectory;
/* ...Existing Application Code... */
@end
AppDelegate.m
Implement applicationDocumentsDirectory, and explicitly write accessor methods for each new property as opposed to simply using the @synthesize keyword.
Note in the persistentStoreCoordinator
accessor there is a location where
you must name the SQLite file used for the store; this should most likely be
your project name.
Remember to properly release each object in dealloc:
@implementation AppDelegate
//Explicitly write Core Data accessors
- (NSManagedObjectContext *) managedObjectContext {
if (managedObjectContext != nil) {
return managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext = [[NSManagedObjectContext alloc] init];
[managedObjectContext setPersistentStoreCoordinator: coordinator];
}
return managedObjectContext;
}
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel != nil) {
return managedObjectModel;
}
managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];
return managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator;
}
NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory]
stringByAppendingPathComponent: @"<Project Name>.sqlite"]];
NSError *error = nil;
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc]
initWithManagedObjectModel:[self managedObjectModel]];
if(![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil URL:storeUrl options:nil error:&error]) {
/* Error for store creation should be handled in here */
}
return persistentStoreCoordinator;
}
- (NSString *)applicationDocumentsDirectory {
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
}
/* ...Existing Application Code... */
- (void)dealloc {
[managedObjectContext release];
[managedObjectModel release];
[persistentStoreCoordinator release];
/* ...Existing Dealloc Releases... */
}
@end
ViewController.h
The following code needs to be added to the interface of whatever view controller
will interact with the Core Data objects.
The FetchedResultsController
and another instance of the ManagedObjectContext
:
@interface ViewController : UIViewController <NSFetchedResultsControllerDelegate> {
NSFetchedResultsController *fetchedResultsController;
NSManagedObjectContext *managedObjectContext;
/* ...Existing Application Code... */
}
@property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
@end
ViewController.m
Don't forget to synthesize the new properties for their accessor methods:
@implementation ViewController
@synthesize fetchedResultsController, managedObjectContext;
/* ...Existing Application Code... */
@end
Add Links and Use Core Data
The managedObjectContext
object has now been created as a property in both the
AppDelegate
and ViewController
classes.
The declaration of managedObjectContext
in the ViewController
must reference
the AppDelegate
, which is the only place that object should be allocated.
Something like
ViewController.managedObjectContext = self.managedObjectContext;
should exist in the applicationDidFinishLaunching method of the AppDelegate
to accomplish this.
Conclusion
Your project should now include all the necessary objects to perform Core Data operations within the application. You can create the data model using Xcode's built-in editor to define entities, properties, and relationships. Then, work with the Core Data framework to store and fetch your persisted object data.