Episode #11

Core Data Basics

22 minutes
Published on April 19, 2012
Core Data is Apple's framework for persisting data on Mac & iOS. It can be though of as an ORM, however it's probably a lot different than most ORMs you've used in the past. In this episode, we'll set up Core Data from scratch so you can see all the moving parts.

Links

  • Episode Sample Code
  • Core Data Book - Marcus Zarra - This is considered the best reference on Core Data out there.
  • iOS Recipes - The data model technique I used in the episode came from this book. Highly recommended!
  • Mogenerator - This tool generates classes based on your data model. I barely scratched the surface of this tool in the screencast, but this is widely used and could be considered standard practice. Be aware, though, that Xmo'd doesn't yet work in Xcode 4, so you'll have to use the script directly.
  • Core Data Programming Guide - Apple's official documentation

Setting up Core Data

// BeersDataModel.h
#import <CoreData/CoreData.h>

@interface BeersDataModel : NSObject

+ (id)sharedDataModel;

@property (nonatomic, readonly) NSManagedObjectContext *mainContext;
@property (nonatomic, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;

- (NSString *)modelName;
- (NSString *)pathToModel;
- (NSString *)storeFilename;
- (NSString *)pathToLocalStore;

@end
// BeersDataModel.m
#import "BeersDataModel.h"

@interface BeersDataModel ()

@property (nonatomic, strong) NSManagedObjectModel *managedObjectModel;
- (NSString *)documentsDirectory;

@end

@implementation BeersDataModel

@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
@synthesize mainContext = _mainContext;

+ (id)sharedDataModel {
    static BeersDataModel *__instance = nil;
    if (__instance == nil) {
        __instance = [[BeersDataModel alloc] init];
    }

    return __instance;
}

- (NSString *)modelName {
    return @"Beers";
}

- (NSString *)pathToModel {
    return [[NSBundle mainBundle] pathForResource:[self modelName]
                                           ofType:@"momd"];
}

- (NSString *)storeFilename {
    return [[self modelName] stringByAppendingPathExtension:@"sqlite"];
}

- (NSString *)pathToLocalStore {
    return [[self documentsDirectory] stringByAppendingPathComponent:[self storeFilename]];
}

- (NSString *)documentsDirectory {
    NSString *documentsDirectory = nil;
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    documentsDirectory = [paths objectAtIndex:0];
    return documentsDirectory;
}

- (NSManagedObjectContext *)mainContext {
    if (_mainContext == nil) {
        _mainContext = [[NSManagedObjectContext alloc] init];
        _mainContext.persistentStoreCoordinator = [self persistentStoreCoordinator];
    }

    return _mainContext;
}

- (NSManagedObjectModel *)managedObjectModel {
    if (_managedObjectModel == nil) {
        NSURL *storeURL = [NSURL fileURLWithPath:[self pathToModel]];
        _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:storeURL];
    }

    return _managedObjectModel;
}

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
    if (_persistentStoreCoordinator == nil) {
        NSLog(@"SQLITE STORE PATH: %@", [self pathToLocalStore]);
        NSURL *storeURL = [NSURL fileURLWithPath:[self pathToLocalStore]];
        NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] 
                                             initWithManagedObjectModel:[self managedObjectModel]];
        NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                                 [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                                 [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
        NSError *e = nil;
        if (![psc addPersistentStoreWithType:NSSQLiteStoreType
                               configuration:nil
                                         URL:storeURL
                                     options:options
                                       error:&e]) {
            NSDictionary *userInfo = [NSDictionary dictionaryWithObject:e forKey:NSUnderlyingErrorKey];
            NSString *reason = @"Could not create persistent store.";
            NSException *exc = [NSException exceptionWithName:NSInternalInconsistencyException
                                                       reason:reason 
                                                     userInfo:userInfo];
            @throw exc;
        }

        _persistentStoreCoordinator = psc;
    }

    return _persistentStoreCoordinator;
}
@end

Generating the entities with Mogenerator

mogenerator --template-var arc=true --model Beers.xcdatamodeld/Beers.xcdatamodel

(Note in the video I had the --template-var setting after the model, and that's why the setting wasn't actually applied)

Saving Data


    NSManagedObjectContext *context = [[BeersDataModel sharedDataModel] mainContext];
    if (context) {
        NSLog(@"Context is ready!");

        Beer *beer = [Beer insertInManagedObjectContext:context];
        beer.name = @"90 Minute Imperial IPA";
        Brewery *brewery = [Brewery insertInManagedObjectContext:context];
        brewery.name = @"Dogfish Head";
        beer.brewery = brewery;

        [context save:nil];
    } else {
        NSLog(@"Context was nil :(");
    }
Want more? Subscribers can view all 573 episodes. New episodes are released regularly.

Subscribe to get access →

Source Code

View on GitHub Download Source