Slide 1

Slide 1 text

Pulling back the curtain on Core Data Chris Mar Spree Commerce http://cmar.me Saturday, February 18, 12

Slide 2

Slide 2 text

Chris Mar • Spree Commerce • iOS and Rails Developer • @cmar • Grassy Knoll Apps - Redskins Radar Saturday, February 18, 12

Slide 3

Slide 3 text

Goal Pull back the curtain on Core Data so you will use it on your next project without fear! (we’ll focus on concepts, not a tutorial) Saturday, February 18, 12

Slide 4

Slide 4 text

Core Data • Object Relational Mapping • Gives you access to a database without using sql or parsing results • Cocoa API with XCode tooling to assist you • Hibernate for Java, ActiveRecord for Rails Saturday, February 18, 12

Slide 5

Slide 5 text

Storage Types • SQLite Database • XML • In-Memory we’ll focus on SQLite Saturday, February 18, 12

Slide 6

Slide 6 text

NSManagedObject • Row from the database • Key-Value coding for fields • Optionally subclass • Fetched from NSManagedObjectContext [employee valueForKey:@"name"]; Saturday, February 18, 12

Slide 7

Slide 7 text

Managed Objects NSManagedObjectContext object1 object2 object1 SQLite Database NSPersistentStoreCoordinator NSManagedObjectModel object2 object1 Saturday, February 18, 12

Slide 8

Slide 8 text

FetchRequest for NSManagedObjects NSFetchRequest *request = [[NSFetchRequest alloc] init]; [request setEntity:[NSEntityDescription entityForName:@"Order" inManagedObjectContext:self.managedObjectContext]]; [request setPredicate:[NSPredicate predicateWithFormat:@"name like %@", @"*7*"]]; NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES]; NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil]; [request setSortDescriptors:sortDescriptors]; self.orders = [self.managedObjectContext executeFetchRequest:request error:&error]; [sortDescriptor release]; [sortDescriptors release]; [request release]; Saturday, February 18, 12

Slide 9

Slide 9 text

The Big 3 NSManagedObjectContext NSPersistentStoreCoordinator NSManagedObjectModel .xcdatamodel sqlite Saturday, February 18, 12

Slide 10

Slide 10 text

NSManagedObjectContext • Object space for Managed Objects • Fetches from Persistent Store • Exclusive to a single thread • Commit and Discard Changes Saturday, February 18, 12

Slide 11

Slide 11 text

NSManagedObjectContext (lazy loaded in AppDelegate) - (NSManagedObjectContext *)managedObjectContext { if (__managedObjectContext != nil) { return __managedObjectContext; } NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; if (coordinator != nil) { __managedObjectContext = [[NSManagedObjectContext alloc] init]; [__managedObjectContext setPersistentStoreCoordinator:coordinator]; } return __managedObjectContext; } Saturday, February 18, 12

Slide 12

Slide 12 text

NSPersistentStoreCoordinator • Manages connections to stores • Maps data model to database • Handles many stores • Shared between threads Saturday, February 18, 12

Slide 13

Slide 13 text

NSPersistentStoreCoordinator (lazy loaded in AppDelegate) - (NSPersistentStoreCoordinator *)persistentStoreCoordinator { if (__persistentStoreCoordinator != nil) { return __persistentStoreCoordinator; } NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"MyApp.sqlite"]; NSError *error = nil; __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) { } return __persistentStoreCoordinator; } Saturday, February 18, 12

Slide 14

Slide 14 text

NSManagedObjectModel • Definition of database schema • Describes entity objects in store • Predefined Queries - Fetch Requests • Relationships between entities Saturday, February 18, 12

Slide 15

Slide 15 text

NSManagedObjectModel (lazy loaded in AppDelegate) - (NSManagedObjectModel *)managedObjectModel { if (__managedObjectModel != nil) { return __managedObjectModel; } NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"MyApp" withExtension:@"momd"]; __managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; return __managedObjectModel; } Saturday, February 18, 12

Slide 16

Slide 16 text

NSManagedObjectModel XCode Editor Saturday, February 18, 12

Slide 17

Slide 17 text

Insert new NSManagedObject NSManagedObject *car = [NSEntityDescription insertNewObjectForEntityForName:@"Car” inManagedObjectContext:self.managedObjectContext]; [car setValue:@"Jeep" forKey:@"name"]; //Save the whole context which will save all the objects in it NSError *error = nil; if ([self.managedObjectContext save:&error]) { NSLog(@"Saved"); } else { NSLog(@"Error saving %@", [error localizedDescription]); } Saturday, February 18, 12

Slide 18

Slide 18 text

Threads Thread1 Thread2 NSManagedObjectContext NSPersistentStoreCoordinator NSManagedObjectContext Object id=1 Object id=1 Pass ID between threads Object id=1 Object id=1 SQLite Database Object id=1 Saturday, February 18, 12

Slide 19

Slide 19 text

Memory Usage • Load into an Array • All in memory • Updates • Fast and Easy for small tables self.orders = [self.managedObjectContext executeFetchRequest:request error:&error]; Saturday, February 18, 12

Slide 20

Slide 20 text

NSFetchedResultsController • Efficiently backs a UITableView • Reduces memory usage • Caches results • Updates table for changes Saturday, February 18, 12

Slide 21

Slide 21 text

NSFetchedResultsController NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:@"Root"]; Saturday, February 18, 12

Slide 22

Slide 22 text

The Big Picture NSManagedObjectContext NSPersistentStoreCoordinator NSManagedObjectModel .xcdatamodel sqlite NSFetchedResultsController iPod touch iPhone iPad Steve Jobs Rocks UITableView NSManagedObject NSManagedObject NSManagedObject NSManagedObject NSManagedObject Saturday, February 18, 12

Slide 23

Slide 23 text

Relationships • to-one • NSManagedObject *manager = [employee valueForKey:@”manager”]; • to-many • NSSet *directReports = [manager valueForKey:@”directReports”]; • Define inverses for data integrity • Delete Rules - nullify, cascade, deny Saturday, February 18, 12

Slide 24

Slide 24 text

Fetched Properties • Lazy loaded query relationship • Sorted • Predicate - filtered • “Give a list of direct reports that begin with the letter C” Saturday, February 18, 12

Slide 25

Slide 25 text

Fetch Requests • Uses NSPredicate for Where clause • Uses NSSortDescriptor for Order By clause • Can be saved with Managed Object Model [fetchRequestTemplateForName] Saturday, February 18, 12

Slide 26

Slide 26 text

Predicates • [NSPredicate predicateWithFormat:@"name CONTAINS[c] %@", searchText]; • @"name BETWEEN %@", [NSArray arrayWithObjects:@”a”,@”b”,nil] • MATCHES for regex • CONTAINS[c] for case insenstivity • AND, OR, NOT Saturday, February 18, 12

Slide 27

Slide 27 text

Default Project with Core Data AppDelegate RootViewController NSManagedObjectContext 1. [awakeFromNib] set managedObjectContext 2. [managedObjectContext] lazy load fetchedResultsController 3. [cellForRowAtIndexPath] lazy load fetchedResultsController Saturday, February 18, 12

Slide 28

Slide 28 text

SQLite Tables Saturday, February 18, 12

Slide 29

Slide 29 text

Z_PRIMARYKEY Saturday, February 18, 12

Slide 30

Slide 30 text

Preloaded Database • Load up database using Base • Base lets you import csv • Make sure you set the primary keys • On start check for existence, then copy it over Saturday, February 18, 12

Slide 31

Slide 31 text

Preloading Database NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"products.sqlite"]; NSURL *storeUrl = [NSURL fileURLWithPath:storePath]; // Put down default db if it doesn't already exist NSFileManager *fileManager = [NSFileManager defaultManager]; if (![fileManager fileExistsAtPath:storePath]) { NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:@"preloaded_products" ofType:@"sqlite"]; if (defaultStorePath) { [fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL]; } } Saturday, February 18, 12

Slide 32

Slide 32 text

FMDB • Objective-C wrapper for SQLite • Direct access • Low overhead • Great for simple data needs • https://github.com/ccgus/fmdb Saturday, February 18, 12

Slide 33

Slide 33 text

FMDB Example FMDatabase *db = [FMDatabase databaseWithPath:@"/tmp/my.db"]; [db open] FMResultSet *rs = [db executeQuery:@"select * from orders where customer_id = ?", @"1000"]; [rs intForColumn:@"c"], [rs stringForColumn:@"b"], [rs dateForColumn:@"d"], [rs doubleForColumn:@"e"]); } [rs close]; [db close]; Saturday, February 18, 12

Slide 34

Slide 34 text

Links • http://www.raywenderlich.com/934/core-data- tutorial-getting-started • http://menial.co.uk/software/base/ • https://github.com/ccgus/fmdb Saturday, February 18, 12

Slide 35

Slide 35 text

Thank You! @cmar on twitter http://cmar.me Saturday, February 18, 12