Core data basic Workshop slides NSSpain 2013

3,715 views

Published on

My slides used at NSSpain 2013 on Core Data

Published in: Technology
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
3,715
On SlideShare
0
From Embeds
0
Number of Embeds
2,465
Actions
Shares
0
Downloads
30
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Core data basic Workshop slides NSSpain 2013

  1. 1. Diego Freniche / @dfreniche / http://www.freniche.com Core Data Workshop
  2. 2. Diego Freniche: programmer & teacher
  3. 3. Diego Freniche: programmer & teacher • @dfreniche • Freelance Mobile developer: iOS/Android/BB10/ webOS/... • In a former life Java Certifications Collector: SCJP 1.5, SCJP 1.6, SCWCD 1.5, SCBCD 1.3 • Some languages: BASIC, PASCAL, C, C++, Delphi, COBOL, Clipper, Visual Basic, Java, JavaScript, Objective-C Hello, World!
  4. 4. Before we start...
  5. 5. Before we start... • Switch OFF phones
  6. 6. Before we start... • Switch OFF phones • Been here is funny
  7. 7. Before we start... • Switch OFF phones • Been here is funny • ¡Live the moment!¡Carpe diem!
  8. 8. Before we start... • Switch OFF phones • Been here is funny • ¡Live the moment!¡Carpe diem! • Ask me a lot. Don’t yawn
  9. 9. Our objective: BUILD things
  10. 10. What you need (checklist) • a Mac with OS X capable of running Xcode 4.6.1 • last Xcode 4 installed 4.6.1 • You can also use prerelease software, if you are a registered Apple developer. No support then, sorry :-D • SimPholders installed: http://simpholders.com • SQLLite database browser: http://sqlitebrowser.sourceforge.net • (optional) set $HOME/Library folder visible, using (from a Terminal)
  11. 11. Diego Freniche / http://www.freniche.com Core Data: developer’s first impression
  12. 12. Diego Freniche / http://www.freniche.com Core Data: developer’s first impression
  13. 13. Diego Freniche / http://www.freniche.com
  14. 14. Diego Freniche / http://www.freniche.com Core Data in 547 easy steps slide 6/320
  15. 15. Diego Freniche / @dfreniche / http://www.freniche.com Core Data terms • Entity • an entity in our model == Object in memory == row in table • Attribute • Relationship • Object graph http://ogre.berniecode.com/ogre_white_paper
  16. 16. Diego Freniche / @dfreniche / http://www.freniche.com Core Data terms • Entity • an entity in our model == Object in memory == row in table • Attribute • Relationship • Object graph http://ogre.berniecode.com/ogre_white_paper
  17. 17. Diego Freniche / @dfreniche / http://www.freniche.com To get the most out of Core Data • KVC, KVO • ARC, memory management • delegate & MVC patterns • singletons are evil (more or less)
  18. 18. Diego Freniche / @dfreniche / http://www.freniche.com Core Data Hello World!
  19. 19. Diego Freniche / @dfreniche / http://www.freniche.com The Problem • Objet - Relational impedance • SQL: 70s/80s • OOP: 80s-
  20. 20. Diego Freniche / @dfreniche / http://www.freniche.com Exhibit 1: composition Person +name: String +idCard: idCard +bankAccout: bankAccount
  21. 21. Diego Freniche / @dfreniche / http://www.freniche.com Exhibit 1: composition Person +name: String +idCard: idCard +bankAccout: bankAccount idCard +number: int +letter: char +checkLetter()
  22. 22. Diego Freniche / @dfreniche / http://www.freniche.com Exhibit 1: composition id name idCard Person +name: String +idCard: idCard +bankAccout: bankAccount idCard +number: int +letter: char +checkLetter()
  23. 23. Diego Freniche / @dfreniche / http://www.freniche.com Exhibit 1: composition id name idCard Person +name: String +idCard: idCard +bankAccout: bankAccount idCard +number: int +letter: char +checkLetter() VARCHAR
  24. 24. Diego Freniche / @dfreniche / http://www.freniche.com Exhibit 1: composition id name idCard Person +name: String +idCard: idCard +bankAccout: bankAccount idCard +number: int +letter: char +checkLetter() VARCHAR ¿?
  25. 25. Diego Freniche / @dfreniche / http://www.freniche.com Employee +empNumber: int Person +name: String +idCard: idCard Exhibit 2: inheritance
  26. 26. Diego Freniche / @dfreniche / http://www.freniche.com Employee +empNumber: int Person +name: String +idCard: idCard Exhibit 2: inheritance Politician +moneyTaken: double
  27. 27. Diego Freniche / @dfreniche / http://www.freniche.com Employee +empNumber: int Person +name: String +idCard: idCard Exhibit 2: inheritance Hyena Politician +moneyTaken: double
  28. 28. Diego Freniche / @dfreniche / http://www.freniche.com Exhibit 3: collection modelling Person +name: String +bills: Bill[] Bill 0..*1 http://en.wikipedia.org/wiki/First_normal_form
  29. 29. Diego Freniche / @dfreniche / http://www.freniche.com Relational World • tables • cartesian products • rows/ columns • normal forms • Objects • object collections • composition • inheritance OO World
  30. 30. Diego Freniche / @dfreniche / http://www.freniche.com Relational World • tables • cartesian products • rows/ columns • normal forms • Objects • object collections • composition • inheritance OO World
  31. 31. Diego Freniche / @dfreniche / http://www.freniche.com The solution: ORM • Object Relational Mapper • Hibernate (Java, .Net) • Core Data (Cocoa) • Core Data is our model • can persist our objects in several ways
  32. 32. Diego Freniche / @dfreniche / http://www.freniche.com The Core Data Stack Managed Object Context Persistent Store Coordinator Persistent Object Store Managed Object Model
  33. 33. Diego Freniche / @dfreniche / http://www.freniche.com Managed Object Context Managed Object Context Persistent Store Coordinator Persistent Object Store Managed Object Model
  34. 34. Diego Freniche / @dfreniche / http://www.freniche.com Our Model NSManagedObjectContext NSManagedObject NSManagedObject NSManagedObject NSManagedObject NSObject PersistedIn memory only
  35. 35. Diego Freniche / @dfreniche / http://www.freniche.com Managed Object Context: MOC • Managed Object Context: in-memory space where CD manages all our model’s objects. • All CRUD is done against a MOC. We persist data using save: • Our model’s objects are Managed Objects. • The MOC needs a Persistent Store Coordinator to save the object graph in persistent store.
  36. 36. Diego Freniche / @dfreniche / http://www.freniche.com Managed Object Model Managed Object Context Persistent Store Coordinator Persistent Object Store Managed Object Model
  37. 37. Diego Freniche / @dfreniche / http://www.freniche.com Managed Object Model • Maps our model objects into database tables. • Objects == NSManagedObject • Classes == NSEntityDescription • We describe our App entities inside a MOM • stored inside .xcdatamodeld files in Xcode. Compiles into .momd • graphic editor / class generator (dumb)
  38. 38. Diego Freniche / @dfreniche / http://www.freniche.com Managed Object Model Managed Object Context Persistent Store Coordinator Persistent Object Store Managed Object Model
  39. 39. Diego Freniche / @dfreniche / http://www.freniche.com Persistent Store Coordinador Managed Object Context Persistent Store Coordinator Persistent Object Store Managed Object Model Makes the mapping between our App’s objects and the physical storage inside the Persistent Object Store. 99% time we’ll work with ONE Object Store, but it’s possible use more than one. For example, a sqlite DB with recipes and another DB with notes, stars, etc. Coordinator: single façade to work with different Stores. A managed object context can then create an object graph based on the union of all the data stores the coordinator covers Coordinator: serializes operations
  40. 40. Diego Freniche / @dfreniche / http://www.freniche.com Persistent Object Store Managed Object Context Persistent Store Coordinator Persistent Object Store Managed Object Model NSXMLStoreType (XML only OS X, bad performance) NSSQLiteStoreType (partial object graph in memory) NSBinaryStoreType (kind of NIBs, poor performance) NSInMemoryStoreType (good for testing) Makes the mapping between our App’s objects and the physical storage inside the Persistent Object Store. Supported Store Types
  41. 41. Diego Freniche / @dfreniche / http://www.freniche.com SQL in SQLite • http://sqlite.org/lang.html • We can see generated SQL: -com.apple.CoreData.SQLDebug 1 • Schemes > Edit Scheme > Test > Arguments
  42. 42. Diego Freniche / @dfreniche / http://www.freniche.com 1 2 3
  43. 43. Diego Freniche / @dfreniche / http://www.freniche.com Accessing SQLite sqlitebrowser.sourceforge.net Look in: /Users/<usuario>/Library/Application Support/iPhone Simulator/<versión>/ Applications/<ID App>/Documents/ <archivo SQLite>
  44. 44. Diego Freniche / @dfreniche / http://www.freniche.com DDL: Data Definition Language • CREATE DATABASE, CREATE TABLE, CREATE INDEX, ALTER TABLE, DROP INDEX, ... • All written by Core Data • We DO NOT have to create anything: neither tables nor database • If we make changes, Core Data alters tables, columns, indexes...
  45. 45. Diego Freniche / @dfreniche / http://www.freniche.com DDL: Data Definition Language • CREATE DATABASE, CREATE TABLE, CREATE INDEX, ALTER TABLE, DROP INDEX, ... • All written by Core Data • We DO NOT have to create anything: neither tables nor database • If we make changes, Core Data alters tables, columns, indexes...
  46. 46. Diego Freniche / @dfreniche / http://www.freniche.com Modelling We need a Data Model file to “draw” our model 1st, create all our model’s entities, then add attributes Can subclass NSManagedObject to use compiler- time name checking, Xcode’s autofill,...
  47. 47. Diego Freniche / @dfreniche / http://www.freniche.com Modelling • New model versions: Editor > Add Model Version • Model (.xcdatamodeld) is a folder • Last version has no number. Oldest with higher number. WTF, Apple! (WTF: What a Tricky Fact) • 1st time we access model it creates persintent store lazily Select THIS
  48. 48. Diego Freniche / @dfreniche / http://www.freniche.com Versioning and changes • Activate always lightweight migration • If we make changes to the model, not changing version, version used in the model and version used to create DB doesn’t match: delete DB. • Reseting Content and Settings.. in Simulator • delete (by hand) .sqlite file
  49. 49. Diego Freniche / @dfreniche / http://www.freniche.com NSManagedObject NSManagedObject NSManagedObjectContext NSEntityDescription
  50. 50. Diego Freniche / @dfreniche / http://www.freniche.com NSManagedObject • base class implementing all “basic” object model behavior • We can NOT use Core Data with NSObject, we HAVE TO use NSManagedObject • Our model classes inherit from NSManagedObject • not mandatory, but... • allows us to add logic, use @property, get notifications... • have to be properly configured
  51. 51. Diego Freniche / @dfreniche / http://www.freniche.com Entities Design • Always add field order • Try to create a good UML diagram at first • Have an NSString constant with every Entity’s name inside .h
  52. 52. Diego Freniche / @dfreniche / http://www.freniche.com Extend NSManagedObject • Editor > Create NSManagedObject subclass... • creates @dynamic properties • getter / setter generated in runtime (@property in compile time) • Core Data doesn’t know at compile time if the persistent store is going to be XML or a DB (or in-memory)
  53. 53. Diego Freniche / @dfreniche / http://www.freniche.com Extend NSManagedObject • overwrite init to call designated initializer
  54. 54. Diego Freniche / @dfreniche / http://www.freniche.com Extend NSManagedObject • overwrite init to call designated initializer -(id)init { NSManagedObjectContext *context = [[CoreDataStack coreDataStack] managedObjectContext]; return [self initWithEntity:[NSEntityDescription entityForName:kRETROITEM_ENTITY inManagedObjectContext:context ] insertIntoManagedObjectContext:context]; }
  55. 55. Diego Freniche / @dfreniche / http://www.freniche.com Validate Properties • One for every property, if we want it • Passing parameter by reference • It should return YES if validation is passed
  56. 56. Diego Freniche / @dfreniche / http://www.freniche.com Validate Properties • One for every property, if we want it • Passing parameter by reference • It should return YES if validation is passed -(BOOL)validateName:(id *)ioValue error:(NSError * __autoreleasing *)outError;
  57. 57. Diego Freniche / @dfreniche / http://www.freniche.com Validator for operations • First thing: must call [super ...] • Useful to check business rules (using several properties)
  58. 58. Diego Freniche / @dfreniche / http://www.freniche.com Validator for operations • First thing: must call [super ...] • Useful to check business rules (using several properties) - (BOOL)validateForDelete:(NSError **)error - (BOOL)validateForInsert:(NSError **)error - (BOOL)validateForUpdate:(NSError **)error
  59. 59. Diego Freniche / @dfreniche / http://www.freniche.com Support for KVO • Good for Faults
  60. 60. Diego Freniche / @dfreniche / http://www.freniche.com Support for KVO • Good for Faults - (void)willAccessValueForKey:(NSString *)key
  61. 61. Diego Freniche / @dfreniche / http://www.freniche.com Inserting Entities (INSERT INTO) insertNewObjectForEntityForName context save Context
  62. 62. Diego Freniche / @dfreniche / http://www.freniche.com Inserting Entities (INSERT INTO) // using NSEntityDescription. Pass: entity name and context [NSEntityDescription insertNewObjectForEntityForName:@”MyEntity” inManagedObjectContext:context]; [retroItem setValue:@"Spectrum 48K" forKey:@"name"]; [retroItem setValue:@100.00 forKey:@"acquisitionCost"]; [retroItem setValue:[NSDate new] forKey:@"dateAcquired"]; insertNewObjectForEntityForName context save Context
  63. 63. Diego Freniche / @dfreniche / http://www.freniche.com Fetching entities (SELECT) • Query with NSFetchRequest • SELECT by definition is unordered • At least we need to provide • entity • order by
  64. 64. Diego Freniche / @dfreniche / http://www.freniche.com Step by Step fetch (Select) 1 2 3 4 5 6
  65. 65. Diego Freniche / @dfreniche / http://www.freniche.com Step by Step fetch (Select) NSManagedObjectContext *context = [[CoreDataStack coreDataStack] managedObjectContext]; NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; NSEntityDescription *entity = [NSEntityDescription entityForName:kRETRO_ITEM_ENTITY inManagedObjectContext:context]; [fetchRequest setEntity:entity]; NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:NO]; [fetchRequest setSortDescriptors:@[sortDescriptor]]; NSError *error = nil; NSArray *distincResults = [context executeFetchRequest:fetchRequest error:&error]; 1 2 3 4 5 6
  66. 66. Diego Freniche / @dfreniche / http://www.freniche.com Order querys NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"fecha_max" ascending:YES]; NSManagedObject returned inside NSArray are unordered unless otherwise we provide NSSortDescription. 1st, we create the sort descriptor [request setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]]; Then we add to our NSFetchRequest the sort descriptors array:
  67. 67. Diego Freniche / @dfreniche / http://www.freniche.com Filtering querys NSManagedObjectContext *moc = [self managedObjectContext]; NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Employee" inManagedObjectContext:moc]; NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease]; [request setEntity:entityDescription]; NSNumber *minimumSalary = ...; NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(lastName LIKE[c] 'Worsley') AND (salary > %@)", minimumSalary]; [request setPredicate:predicate]; NSError *error = nil; NSArray *array = [moc executeFetchRequest:request error:&error]; NSFetchRequest returns an array of NSManagedObject. We can use a NSPredicate to filter. Filter/NSPredicate acts here as the SQL WHERE clause. We need to add that query with setPredicate.
  68. 68. Diego Freniche / @dfreniche / http://www.freniche.com Delete Entities (DELETE) + (void)deleteInstancesForEntityName:(NSString *)entityName inContext:(NSManagedObjectContext *)context { NSFetchRequest *fetch = [[NSFetchRequest alloc] init]; [fetch setEntity:[NSEntityDescription entityForName:entityName inManagedObjectContext:context]]; NSError *error = nil; NSArray *dataObjects = [context executeFetchRequest:fetch error:&error]; for (NSManagedObject *dataObject in dataObjects) { [context deleteObject:dataObject]; } NSError *saveError = nil; [context save:&saveError]; }
  69. 69. Diego Freniche / @dfreniche / http://www.freniche.com Object identificator
  70. 70. Diego Freniche / @dfreniche / http://www.freniche.com Object identificator NSManagedObjectID *moID = [managedObject objectID]; -(NSManagedObject *)existingObjectWithID:(NSManagedObjectID *)objectID error:(NSError **)error
  71. 71. Diego Freniche / @dfreniche / http://www.freniche.com Accessing Properties Sometimes we don’t want the whole object (NSManagedObject) only the value of a property applying a function (max, min, etc.). NSFetchRequest *request = [[NSFetchRequest alloc] init]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:context]; [request setEntity:entity]; 1. Create NSFetchRequest as usual [request setResultType:NSDictionaryResultType]; 2. Tell NSFetchRequest to return NSDictionary instead NSArray: NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:@"creationDate"]; NSExpression *minExpression = [NSExpression expressionForFunction:@"min:" arguments:[NSArray arrayWithObject:keyPathExpression]]; 3. Define the field to calc upon (NSExpression), then the function
  72. 72. Diego Freniche / @dfreniche / http://www.freniche.com Accessing Properties NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init]; [expressionDescription setName:@"minDate"]; [expressionDescription setExpression:minExpression]; [expressionDescription setExpressionResultType:NSDateAttributeType]; 4. Create a NSExpressionDescription: [request setPropertiesToFetch:[NSArray arrayWithObject:expressionDescription]]; NSArray *objects = [managedObjectContext executeFetchRequest:request error:&error]; 5. Set in the query the properties to fetch if ([objects count] > 0) { NSLog(@"Minimum date: %@", [[objects objectAtIndex:0] valueForKey:@"minDate"]); } 6. Access our result:
  73. 73. Diego Freniche / @dfreniche / http://www.freniche.com Relationship example NSManagedObjectContext *context = [self managedObjectContext]; NSManagedObject *failedBankInfo = [NSEntityDescription insertNewObjectForEntityForName:@"FailedBankInfo" inManagedObjectContext:context]; [failedBankInfo setValue:@"Test Bank" forKey:@"name"]; [failedBankInfo setValue:@"Testville" forKey:@"city"]; [failedBankInfo setValue:@"Testland" forKey:@"state"]; NSManagedObject *failedBankDetails = [NSEntityDescription insertNewObjectForEntityForName:@"FailedBankDetails" inManagedObjectContext:context]; [failedBankDetails setValue:[NSDate date] forKey:@"closeDate"]; [failedBankDetails setValue:[NSDate date] forKey:@"updateDate"]; [failedBankDetails setValue:[NSNumber numberWithInt:12345] forKey:@"zip"]; [failedBankDetails setValue:failedBankInfo forKey:@"info"]; [failedBankInfo setValue:failedBankDetails forKey:@"details"]; NSError *error; if (![context save:&amp;error]) { NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]); } Escritura
  74. 74. Diego Freniche / @dfreniche / http://www.freniche.com Relationship example NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"FailedBankInfo" inManagedObjectContext:context]; [fetchRequest setEntity:entity]; NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error]; for (NSManagedObject *info in fetchedObjects) { NSLog(@"Name: %@", [info valueForKey:@"name"]); NSManagedObject *details = [info valueForKey:@"details"]; NSLog(@"Zip: %@", [details valueForKey:@"zip"]); } Read
  75. 75. Diego Freniche / @dfreniche / http://www.freniche.com NSFetchedResultsController • Controller without interface • Purpose: “feed” with data an UITableView • Protocol NSFetchedResultsControllerDelegate • section “Typical Use”: there’s the code found in template • connected to a Context: if there are changes of any object inside that context it receives a notification and updates automatically
  76. 76. Diego Freniche / @dfreniche / http://www.freniche.com NSFetchedResultsController SQLite UITableView
  77. 77. Diego Freniche / @dfreniche / http://www.freniche.com NSFetchedResultsController SQLite UITableView ???
  78. 78. Diego Freniche / @dfreniche / http://www.freniche.com NSFetchedResultsController Context NSManagedObject NSManagedObject NSManagedObject SQLite UITableView ???
  79. 79. Diego Freniche / @dfreniche / http://www.freniche.com NSFetchedResultsController Context NSManagedObject NSManagedObject NSManagedObject SQLite UITableView NSFetchedResultsController ??? delegate
  80. 80. Diego Freniche / @dfreniche / http://www.freniche.com NSFetchedResultsController Context NSManagedObject NSManagedObject NSManagedObject SQLite UITableView NSFetchedResultsController ??? delegate
  81. 81. Diego Freniche / @dfreniche / http://www.freniche.com NSFetchedResultsController Context NSManagedObject NSManagedObject NSManagedObject SQLite UITableView NSFetchedResultsController delegate
  82. 82. Diego Freniche / @dfreniche / http://www.freniche.com Attributions • http://www.flickr.com/photos/paldies/85684217/ • http://www.flickr.com/photos/56380734@N05/6808753611/ • http://www.flickr.com/photos/msimdottv/4339697089/ • http://www.flickr.com/photos/mobilestreetlife/4179063482/ • http://www.flickr.com/photos/owldreams/4428782193/ • http://www.flickr.com/photos/miss_pupik/73160522/ • http://kfannerd713.deviantart.com/art/UNICORN-PUKING-RAINBOWS-WHAAAA-152117816 • http://www.flickr.com/photos/wwworks/4759535950/ • http://www.flickr.com/photos/barto/28135419/sizes/l/in/photolist-3ucFr-7aiwZ-aqWUu-bLebi-cDeVC-jt2YW-jWW1t-kQ25f-m86XP-swafK-yHMbE-yHMcc-yHMda-

×