Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Pulling back the curtain on Core Data

Chris Mar
February 18, 2012

Pulling back the curtain on Core Data

From iOSDevCampDC 2011. What happens when you build a new core data project? Take a look at the objects involved in using core data in your applications.

Chris Mar

February 18, 2012
Tweet

More Decks by Chris Mar

Other Decks in Programming

Transcript

  1. Pulling back the curtain on Core Data Chris Mar Spree

    Commerce http://cmar.me Saturday, February 18, 12
  2. Chris Mar • Spree Commerce • iOS and Rails Developer

    • @cmar • Grassy Knoll Apps - Redskins Radar Saturday, February 18, 12
  3. 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
  4. 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
  5. Storage Types • SQLite Database • XML • In-Memory we’ll

    focus on SQLite Saturday, February 18, 12
  6. NSManagedObject • Row from the database • Key-Value coding for

    fields • Optionally subclass • Fetched from NSManagedObjectContext [employee valueForKey:@"name"]; Saturday, February 18, 12
  7. 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
  8. NSManagedObjectContext • Object space for Managed Objects • Fetches from

    Persistent Store • Exclusive to a single thread • Commit and Discard Changes Saturday, February 18, 12
  9. 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
  10. NSPersistentStoreCoordinator • Manages connections to stores • Maps data model

    to database • Handles many stores • Shared between threads Saturday, February 18, 12
  11. 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
  12. NSManagedObjectModel • Definition of database schema • Describes entity objects

    in store • Predefined Queries - Fetch Requests • Relationships between entities Saturday, February 18, 12
  13. 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
  14. 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
  15. 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
  16. 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
  17. NSFetchedResultsController • Efficiently backs a UITableView • Reduces memory usage

    • Caches results • Updates table for changes Saturday, February 18, 12
  18. 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
  19. 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
  20. 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
  21. 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
  22. 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
  23. 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
  24. 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
  25. 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
  26. FMDB • Objective-C wrapper for SQLite • Direct access •

    Low overhead • Great for simple data needs • https://github.com/ccgus/fmdb Saturday, February 18, 12
  27. 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