Listing One shows how we might implement the database file cycle in a custom class. The class, FooTriage
, declares three protected properties (lines 4-6) for three Core Data classes. In its init
method (line 22), FooTriage
invokes prepModel
, which creates an instance of NSManagedObjectModel
using initWithContentsOfURL:
(lines 61-62). To that init
method, it sends the path to the resource file FooTriage.momd
. This file sits inside the application bundle (lines 54-56), and it contains the database schema defined earlier. The prepModel
method ends by storing the NSManagedObjectModel
instance into the property dbModel
.
// -- Declaring the class interface @interface FooTriage : NSObject { NSManagedObjectContext *dbContext; NSManagedObjectModel *dbModel; NSPersistentStoreCoordinator *dbSource; } - (void)prepModel; - (void)link2file; - (void)save2file; @end // -- Implementing the class @implementation FooTriage // Initialising the class - (id)init { // initialise the parent if (self = [super init]) { [self prepModel]; [self link2file]; return (self); } else // the parent failed to initialise return (nil); } // Disposing the class - (void)dealloc { // save any database changes [self save2file]; // dispose the following properties [dbContext release]; [dbModel release]; [dbSource release]; // invoke the parent method [super dealloc]; } // Preparing the object model - (void)prepModel { NSString *tPth; NSURL *tURL; // set the schema location tPth = [[NSBundle mainBundle] pathForResource:@"FooTriage" ofType:@"momd"]; tURL = [NSURL fileURLWithPath:tPth]; // load the schema dbModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:tURL]; } // Linking to the database file - (void)link2file { NSURL *tURL; NSError *tErr = nil; BOOL tChk; // set the file location tURL = [NSURL fileURLWithPath:[[self applicationDocumentsDirectory] stringByAppendingPathComponent:@"FooTriage.sqlite"]]; // create the coordinator dbSource = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:dbModel]; if (dbSource != nil) { // initialise the coordinator tChk = [dbSource addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:tURL options:nil error:&tErr]; if (tChk) { // prepare the object context dbContext = [[NSManagedObjectContext alloc] init]; [dbContext setPersistentStoreCoordinator:dbSource]; } else NSLog(@"failure"); } } // Saving changes into the file - (void)save2file { NSError *tErr = nil; BOOL tChk; // check for a valid context tChk = (dbContext != nil); if (tChk) { // does it have pending changes? tChk = [dbContext hasChanges]; if (tChk) // update the database file tChk = [dbContext save:&tErr]; } // check the save outcome if (tChk) NSLog(@"successful save"); else NSLog(@"failed save"); } @endListing One.
Next, FooTriage
invokes the method link2file
(line 23). This method makes an instance of NSPersistentStoreCoordinator
and links it with the property dbModel
(lines 78-79). It also stores the instance into the property dbSource
. Then the link2file
method preps dbSource
with the method addPersistentStoreWithType…
(lines 83-86). To that method it sends the path to the database file FooTriage.sqlite
and an NSError
object. When addPersistentStoreWithType…
returns a YES
, link2file
creates an instance of NSManagedObjectContext
(lines 90-91) and stores it in the property dbContext
. It then connects dbContext
to dbSource
using the method setPersistentStoreCoordinator:
(lines 92-93).
In its dealloc
method (line 36), FooTriage
invokes its method save2file
. This method checks the property dbContext
for a valid instance of NSManagedObjectContext
and for any pending changes (lines 107-111). If both are true, save2file
calls the save: method
(line 114), passing along an NSError
object for input. Afterwards, FooTriage
disposes of each property with a release message and invokes its parent's dealloc method (lines 39-44).
Working with Database Records
A typical record transaction can be one of four basic tasks: retrieval, insertion, edition, and deletion. Except for retrieval, these tasks alter the database by adding new records or changing existing records. The alterations are always queued to allow for undos and to protect the database file from unwanted changes.
Listing Two shows how to prepare a constant table. This method, initInjury
, adds eight records to the table Injury. It starts with a sequence of injury terms, each term delimited by a '%'
token (line 11). It then uses the NSString
method componentsSeparatedByString:
to divide the terms and hold them in an NSArray
object (line 13).
- (void)initInjury { NSString *tInj, *tNom; NSUInteger tIdx, tKey, tCnt; NSArray *tLst; NSError *tErr = nil; NSManagedObject *tRec; // define the list of injuries tInj = @"Blunt Trauma%Burn%C-Spine%Cardiac%Crushing%Fracture%Laceration%Penetration"; tLst = [tInj componentsSeparatedByString:@"%"]; tCnt = [tLst count]; // start adding the categories for (tIdx = 0; tIdx < tCnt; tIdx++) { // create a new record tRec = [NSEntityDescription insertNewObjectForEntityForName:@"Injury" inManagedObjectContext:dbContext]; if (tRec != nil) { // read an injury name tNom = [tLst objectAtIndex:tIdx]; // prepare the record tKey = tIdx; [tRec setValue:[NSNumber numberWithInt:tKey] forKey:@"id"]; [tRec setValue:tNom forKey:@"name"]; // insert the record [dbContext insertObject:tRec]; } } // ...commit the records to make them available }
Listing Two.