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

Core Data - App-Design, Nested ManagedObjectContexts, Migration

Karl Bode
October 22, 2012

Core Data - App-Design, Nested ManagedObjectContexts, Migration

Vortrag auf der iPhone Developer Conference 2012 in Stuttgart

Karl Bode

October 22, 2012
Tweet

More Decks by Karl Bode

Other Decks in Programming

Transcript

  1. Karl Bode • Software-Entwickler - mobile • hot coffee apps,

    Bremen • Digital Media - Master Student • Twitter: @karl_in • [email protected] 2
  2. Core Data 101 • in OS X seit 10.4 (Tiger),

    in iOS seit 3.0 • schema-driven object graph management and persistence framework • SQLite ist eine Option • fest verankert in Xcode-Templates • grafische Datenmodellierung -> Schema 5
  3. Core Data 101 • versionierte Datenmodelle + Migration • Undo

    + Redo - Unterstützung • iCloud-Synchronisation • zahlreiche Optimierungen • eine Technologie für komplexe Aufgaben 6
  4. • Personen anlegen und in einer Tabelle anzeigen • eBay-Query

    hinterlegen • Auktionen abrufen, anzeigen, speichern • später auf github.com/kpbode 9 Die Sample-App
  5. Daten modellieren KPBPerson - name : String (required) - query

    : String (required) KPBAuction - title : String (required) - subtitle : String (optional) - image : Image (optional) - url : String (required) 10 0..1 0..*
  6. Daten modellieren • Tabellen -> Entitäten • Spalten -> Attribute

    • Standard-Typen ( String, Integer, Bool, ... ) • Binäre Attribute (z.B. für Images) Achtung! • Eigene Serialisierung (z.B. für Arrays) -> Transformables Achtung! 11
  7. 14

  8. Core Data initialisieren 16 // The model is compiled to

    a binary momd-File NSURL *modelURL = [mainBundle URLForResource:@"GiftIdeas" withExtension:@"momd"]; // initialized an instance of NSManagedObjectModel with this URL NSManagedObjectModel *managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
  9. Core Data initialisieren 17 // Initialize an instance of NSPersistentStoreCoordinator

    with the model NSPersistentStoreCoordinator *persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:managedObjectModel]; // URL to the location of the sqlite NSURL *documentsDirectory = [self applicationDocumentsDirectory]; NSURL *storeURL = [documentsDirectory URLByAppendingPathComponent:@"GiftIdeas.sqlite"]; // Add a store with the specified URL to the StoreCoordinator NSError *error = nil; if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) { NSLog(@"Failed to add PersistentStore: %@", [error userInfo]); }
  10. Core Data initialisieren 18 //setup the managedObjectContext with the persistentStoreCoordinator

    NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init]; moc.persistentStoreCoordinator = persistentStoreCoordinator; // start using your managedObjectContext ...
  11. Core Data initialisieren • Initialisierung in eigene Klasse auslagern •

    Inilialisierung als Klassenmethode für NSManagedObjectContext: • KPB_createManagedObjectContextWithS toryType: modelName: storeFileURL: • Konstanten verwenden! 19
  12. Objekte laden 21 NSManagedObjectContext NSManagedObject NSManagedObject NSManagedObject NSManagedObject ? •

    SELECT * FROM `persons`; • NSFetchRequest • NSFetchedResultsController
  13. Objekte laden 22 // setup the basic NSFetchRequest NSFetchRequest *fetchRequest

    = [NSFetchRequest fetchRequestWithEntityName:@"Person"]; // specify how to sort the fetched data fetchRequest.sortDescriptors = @[ [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]]; // initialize a NSFetchedResultsController to handle fetched data NSFetchedResultsController *fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:nil]; // register as a delegate to react to changes to the fetched data fetchedResultsController.delegate = self;
  14. Objekte anzeigen 23 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return [[self.fetchedResultsController sections]

    count]; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { id<NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section]; return [sectionInfo numberOfObjects]; }
  15. Objekte anzeigen 24 - (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath { KPBPerson

    *person = [self.fetchedResultsController objectAtIndexPath:indexPath]; cell.textLabel.text = person.name; cell.detailTextLabel.text = person.query; }
  16. Objekte erstellen 25 NSManagedObjectContext NSManagedObject // create and insert a

    new instance with the entity name into context KPBPerson *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:managedObjectContext]; NSManagedObjectModel NSEntityDescription ...
  17. 26 Objekte verwalten KPBPersonsListViewController @property ... *managedObjectContext KPBEditPersonViewController @property ...

    *managedObjectContext @property ... KPBPerson *person Hinzufügen • neues Person-Objekt • managedObjectContext KPBPersonsListViewControllerDelegate Gespeichert Abgebrochen KPBEditPersonViewController @property ... *managedObjectContext @property ... KPBPerson *person Bearbeiten • ausgewähltes Person- Objekt • managedObjectContext
  18. 27

  19. Lösungsansätze • Objekt als temporär markieren • ViewController-Outlets auslesen •

    Transferobjekte / NSDictionaries • NSUndoManager ‣ ManagedObjectContext-Snapshot erstellen und nach Bedarf verwerfen 28
  20. Nested MOCs • moc.parentContext • Child: Snapshot von Parent •

    ConfinementTypes • Verwendung von Queues / Threads 30 Neu
  21. Core Data & Threading • ein Thread pro ManagedObjectContext •

    Zugriff nur mit Objekten aus dem selben ManagedObjectContext oder per objectID ‣ Probleme bei längeren Operationen, Disk-IO 31
  22. Confinement-Types • NSConfinementConcurrencyType • Standard-Type / Default • NSMainQueueConcurrencyType •

    Main- /UI-Queue • NSPrivateQueueConcurrencyType • private Queue / Background 32
  23. Nested MOCs 33 [moc performBlock:^{ // do something on this

    context on this queue }]; [moc performBlockAndWait:^{ // do something on this context on this queue and wait }];
  24. Nested MOCs 35 // create a new managedObjectContext which is

    a child of the current NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; moc.parentContext = masterManagedObjectContext; ... // save if needed NSError *saveError = nil; if (![moc save:&saveError]) { NSLog(@"failed to save context: %@", saveError); } else { // persist to disk if needed by saving the root context // use a block to save the context on its own queue [masterManagedObjectContext performBlock:^{ NSError *masterSaveError = nil; if (![masterManagedObjectContext save:&masterSaveError]) { NSLog(@"failed to save master: %@", masterSaveError); } }]; }
  25. 37

  26. 39

  27. 41

  28. 43

  29. Datenmigration • 1.0 - Hurra! • Neue Features -> Datenmodell

    anpassen • Was passiert mit bestehenden Daten? ‣ Core Data to the rescue 48
  30. Inferred-Migration • Migration innerhalb der Datenbank mit Boardmitteln • Annahmen

    über die durchzuführenden Änderungen werden getroffen • alle Änderungen müssen aus dem neuen Datenmodell hervorgehen 50
  31. Inferred-Migration 51 KPBPerson - name : String (required) - query

    : String (required) KPBAuction - title : String (required) - subtitle : String (optional) - image : Image (optional) - url : String (required) - serverId : String (optional) 0..1 0..*
  32. 54

  33. Mapping-Model • Anlegen per Xcode-Assistant • Mappings für Entitäten, Attribute

    und Beziehungen werden erstellt • Value-Expression für simples Kopieren, Rechnungen, Bedingungen • MOCs werden für die Migration erstellt -> Achtung! Speicher 55
  34. Custom Code • Mapping-Model erstellen • Policy / Klassennamen für

    Entitätenmapping ausweisen • Migration erfolgt durch Methodenaufrufe der Subklasse 56
  35. Custom Code 57 beginEntityMapping: manager: error: endEntityMapping: entityMapping: manager: error

    createDestinationInstancesForSourceInstance: entityMapping: manager: error endInstanceCreationForEntityMapping: entityMapping: manager: error pro Object performCustomValidationForEntityMapping: entityMapping: manager: error createRelationshipsForDestinationInstance: entityMapping: manager: error endRelationshipCreationForEntityMapping: entityMapping: manager: error pro Object
  36. 58 Custom Code KPBPerson - name : String (required) -

    query : String (required) KPBAuction - title : String (required) - subtitle : String (optional) - image : Image (optional) - url : String (required) - serverId : String (optional) 1 0..* KPBSearchKeyword - term : String (required) 1 0..* Query in Keywords umwandeln
  37. 60

  38. Datenmigration • Core Data sucht sich den kürzesten Weg ->

    testen, testen, testen • Inferred-Migration verwenden (wenn möglich) 61
  39. Zusammenfassung • Core Data? Trau dich! (wenn du die Kanone

    brauchst) • Nested Contexts? Aber ja! (möglichst ab iOS 6) • Migration? Keep it simple! 63
  40. Quellen • “Core Data Programming Guide”, Apple • “Core Data

    for iOS”, Tim Isted und Tom Harrington • “Core Data”, Marcus S. Zarra 66