CoreData - there is an ORM you can like!

1,052 views

Published on

It doesn't hate you. CoreData is Cocoa for models! But it bites. I show you WHY and WHEN to use CoreData as well as HOW in order to prevent be biten by it.

This slides were presented on my presentation at iCONdev at iCONprague 2014 on 23. 3. 2014 (more at http://www.iconprague.com/detailni-program/#core-data-i-orm-muzete-mit-radi)

Published in: Technology
1 Comment
1 Like
Statistics
Notes
No Downloads
Views
Total views
1,052
On SlideShare
0
From Embeds
0
Number of Embeds
40
Actions
Shares
0
Downloads
9
Comments
1
Likes
1
Embeds 0
No embeds

No notes for slide

CoreData - there is an ORM you can like!

  1. 1. Tomáš Jukin @Inza Core Data there is an ORM you can like!
  2. 2. Core Data?
  3. 3. Core Data? -- It’s a big hairy mess!
  4. 4. Core Data? -- It’s a big hairy mess! YES! but Why?
  5. 5. Core Data? -- It’s a big hairy mess! YES! but Why? Real problems are hard.
  6. 6. Core Data? -- It’s a big hairy mess! YES! but Why? Real problems are hard. Really?
  7. 7. Core Data? -- It’s a big hairy mess! YES! but Why? Real problems are hard. Really? Really.
  8. 8. Core Data? -- It’s a big hairy mess! YES! but Why? Real problems are hard. Really? Really. CoreData is hairy
  9. 9. Core Data? -- It’s a big hairy mess! YES! but Why? Real problems are hard. Really? Really. CoreData is hairy because it ...
  10. 10. Core Data? -- It’s a big hairy mess! YES! but Why? Real problems are hard. Really? Really. CoreData is hairy because it ... ... solves real problems!
  11. 11. Tomáš Jukin @Inza www.juicymo.cz @JuicymoCZ
  12. 12. 1) WHY and WHEN to use Core Data?
  13. 13. 1) WHY and WHEN to use Core Data? 2) HOW to use Core Data?
  14. 14. WHY?
  15. 15. 1) Death
  16. 16. 1) Death 2) Taxes
  17. 17. 1) Death 2) Taxes 3) SW Requirements WILL change
  18. 18. “Do you understand how to structure real-world data access for Mac and iOS applications better than Apple?”
  19. 19. “Do you understand how to structure real-world data access for Mac and iOS applications better than Apple?” -- Nope.
  20. 20. • Handling future changes to the data schema • Bi-directional sync with servers • Bi-directional sync with peers (e.g. iPad <-> iPhone) • Undo - Redo • Multithreading long-running operations • Sync data between multiple threads • Notifying faraway code about changes to objects so that they can refresh or update at appropriate intervals Has your own so-called “data stack” features like this?
  21. 21. Do I need these features? (= WHEN?)
  22. 22. But if... I NEVER update my app! My users NEVER do mistakes! I NEVER use threads! My app is just one view! My data operations ARE all instantaneous! Requirements of my apps NEVER changes!
  23. 23. 1) Death 2) Taxes 3) SW Requirements WILL change
  24. 24. ... all of that is TRUE for you Core Data is NOT for you.
  25. 25. ... all of that is TRUE for you Core Data is NOT for you. Otherwise you SHOULD use it.
  26. 26. Core Data = Do not implement Do not test Do not optimize
  27. 27. Core Data = Do not implement Do not test Do not optimize Data Stack code used by your app! Apple has already done that!
  28. 28. Fact Apple’s high-level APIs can be much faster than YOUR “optimized” code at lower levels
  29. 29. Fact Example: Fast Image? ➜ UIImageView
  30. 30. Fact CoreData is Cocoa for Models
  31. 31. Cocoa for Models Is UIButton easy? Is UITableView easy? Is Delegation Pattern easy? Is InterfaceBuilder and outlets easy?
  32. 32. Cocoa for Models Is UIButton easy? Is UITableView easy? Is Delegation Pattern easy? Is InterfaceBuilder and outlets easy? NOPE!
  33. 33. Cocoa for Models Are they powerful?
  34. 34. Cocoa for Models Are they powerful? YES!
  35. 35. Why NOT to use Core Data? •Programmer naivity
  36. 36. •Programmer naivity ➜ “My app isn’t complex enought” = I am too lazy to learn it Why NOT to use Core Data?
  37. 37. •Programmer naivity ➜ “My app isn’t complex enought” = I am too lazy to learn it ➜ “I dont like large frameworks - I used them in HALF of my app and it was so much work!” = Use entirely it or not. Otherwise it will not save time & effort Why NOT to use Core Data?
  38. 38. •Programmer naivity ➜ “My app isn’t complex enought” = I am too lazy to learn it ➜ “I dont like large frameworks - I used them in HALF of my app and it was so much work!” = Use entirely it or not. Otherwise it will not save time & effort •Willful ignorance Why NOT to use Core Data?
  39. 39. •Programmer naivity ➜ “My app isn’t complex enought” = I am too lazy to learn it ➜ “I dont like large frameworks - I used them in HALF of my app and it was so much work!” = Use entirely it or not. Otherwise it will not save time & effort •Willful ignorance ➜ “I don’t have any idea what I’m talking about, but it sounds like a bad idea to me” = What? Why NOT to use Core Data?
  40. 40. So? Reading code is hard Writing code is easy Why learn when we can re-invent? Really? If this works in your world, Core Data is not for you...
  41. 41. OK, but when seriously NO? Update HUGE part of DB in one moment Working with lots of records ➜ RSS Reader app
  42. 42. Still not ready to use Core Data? Read this: goo.gl/Flzrsk Numbers here: goo.gl/lNFjdr
  43. 43. HOW?
  44. 44. .sqlite Schema App
  45. 45. .sqlite ORM Schema App
  46. 46. .sqlite App Core Data Schema App .sqlite Web Store
  47. 47. .sqlite App Schema App .sqlite Web Store NSManaged ObjectContext NSManaged ObjectContext NSManaged ObjectModel Persistent ObjectStore Persistent ObjectStore Persistent ObjectStore Persistent Store Coordinator
  48. 48. .sqlite App Schema App .sqlite Web Store NSManaged Object NSManaged Object NSManaged Object NSManaged ObjectContext NSManaged ObjectContext NSManaged ObjectModel Persistent ObjectStore Persistent ObjectStore Persistent ObjectStore Persistent Store Coordinator
  49. 49. ...Complex ORM => Complex Setup
  50. 50. Setup
  51. 51. // In the AppDelegate.h @property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext; @property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel; @property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;   - (void)saveContext; - (NSURL *)applicationDocumentsDirectory;   // In the AppDelegate.m - (void)applicationWillTerminate:(UIApplication *)application { // Saves changes in the application's managed object context before the application terminates. [self saveContext]; }   - (void)saveContext { NSError *error = nil; NSManagedObjectContext *managedObjectContext = self.managedObjectContext; if (managedObjectContext != nil) { if ([managedObjectContext hasChanges] &amp;&amp; ![managedObjectContext save:&amp;error]) { NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } } }   #pragma mark - Core Data stack   /** Returns the managed object context for the application. If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application. */ - (NSManagedObjectContext *)managedObjectContext { if (__managedObjectContext != nil) { return __managedObjectContext; }   NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; if (coordinator != nil) { __managedObjectContext = [[NSManagedObjectContext alloc] init]; [__managedObjectContext setPersistentStoreCoordinator:coordinator]; } return __managedObjectContext; }   /** Returns the managed object model for the application. If the model doesn't already exist, it is created from the application's model. */ - (NSManagedObjectModel *)managedObjectModel { if (__managedObjectModel != nil) { return __managedObjectModel; } NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"blaba" withExtension:@"momd"]; __managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; return __managedObjectModel; }   /** Returns the persistent store coordinator for the application. If the coordinator doesn't already exist, it is created and the application's store added to it. */ - (NSPersistentStoreCoordinator *)persistentStoreCoordinator { if (__persistentStoreCoordinator != nil) { return __persistentStoreCoordinator; }   NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"blaba.sqlite"];   NSError *error = nil; __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&amp;error]) { NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); }   return __persistentStoreCoordinator; }   #pragma mark - Application's Documents directory   /** Returns the URL to the application's Documents directory. */ - (NSURL *)applicationDocumentsDirectory { return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; }
  52. 52. 99 rows!
  53. 53. Really ?!
  54. 54. Core Data bites!
  55. 55. The Cure 1) MagicalRecord github.com/magicalpanda/MagicalRecord
  56. 56. The Cure 1) MagicalRecord github.com/magicalpanda/MagicalRecord 2) Mogenerator github.com/rentzsch/mogenerator
  57. 57. The Cure 1) MagicalRecord github.com/magicalpanda/MagicalRecord 2) Mogenerator github.com/rentzsch/mogenerator + CocoaPods (as usual)
  58. 58. Magical Record
  59. 59. Magical Record Nice (Rails like) API on Core Data
  60. 60. Magical Record Nice (Rails like) API on Core Data You still can dive in!
  61. 61. // In the AppDelegate.h @property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext; @property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel; @property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;   - (void)saveContext; - (NSURL *)applicationDocumentsDirectory;   // In the AppDelegate.m - (void)applicationWillTerminate:(UIApplication *)application { // Saves changes in the application's managed object context before the application terminates. [self saveContext]; }   - (void)saveContext { NSError *error = nil; NSManagedObjectContext *managedObjectContext = self.managedObjectContext; if (managedObjectContext != nil) { if ([managedObjectContext hasChanges] &amp;&amp; ![managedObjectContext save:&amp;error]) { NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } } }   #pragma mark - Core Data stack   /** Returns the managed object context for the application. If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application. */ - (NSManagedObjectContext *)managedObjectContext { if (__managedObjectContext != nil) { return __managedObjectContext; }   NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; if (coordinator != nil) { __managedObjectContext = [[NSManagedObjectContext alloc] init]; [__managedObjectContext setPersistentStoreCoordinator:coordinator]; } return __managedObjectContext; }   /** Returns the managed object model for the application. If the model doesn't already exist, it is created from the application's model. */ - (NSManagedObjectModel *)managedObjectModel { if (__managedObjectModel != nil) { return __managedObjectModel; } NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"blaba" withExtension:@"momd"]; __managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; return __managedObjectModel; }   /** Returns the persistent store coordinator for the application. If the coordinator doesn't already exist, it is created and the application's store added to it. */ - (NSPersistentStoreCoordinator *)persistentStoreCoordinator { if (__persistentStoreCoordinator != nil) { return __persistentStoreCoordinator; }   NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"blaba.sqlite"];   NSError *error = nil; __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&amp;error]) { NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); }   return __persistentStoreCoordinator; }   #pragma mark - Application's Documents directory   /** Returns the URL to the application's Documents directory. */ - (NSURL *)applicationDocumentsDirectory { return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; } CD
  62. 62. 99 rows!
  63. 63. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *) launchOptions { [MagicalRecord setupCoreDataStackWithStoreNamed: @"MyDatabase.sqlite"]; // ... return YES; }   - (void)applicationWillTerminate:(UIApplication *) application { [MagicalRecord cleanUp]; } MR
  64. 64. 11 rows!
  65. 65. Fetch
  66. 66. NSArray  *fetchedObjects; NSManagedObjectContext  *context  =  [self   managedObjectContext]; NSFetchRequest  *fetch  =  [[NSFetchRequest  alloc]  init]; NSEntityDescription  *entityDescription  =   [NSEntityDescription  entityForName:@"Person"     inManagedObjectContext:context]; [fetch  setEntity:entityDescription]; [fetch  setPredicate:[NSPredicate   predicateWithFormat:@"age  =  %d",  25]]; NSError  *error  =  nil; fetchedObjects  =  [context   executeFetchRequest:fetch  error:&error]; if([fetchedObjects  count]  ==  1)        return  [fetchedObjects  objectAtIndex:0]; else        return  nil; CD
  67. 67. NSArray  *fetchedObjects; NSManagedObjectContext  *context  =  [self   managedObjectContext]; NSFetchRequest  *fetch  =  [[NSFetchRequest  alloc]  init]; NSEntityDescription  *entityDescription  =   [NSEntityDescription  entityForName:@"Person"     inManagedObjectContext:context]; [fetch  setEntity:entityDescription]; [fetch  setPredicate:[NSPredicate   predicateWithFormat:@"age  =  %d",  25]]; NSError  *error  =  nil; fetchedObjects  =  [context   executeFetchRequest:fetch  error:&error]; if([fetchedObjects  count]  ==  1)        return  [fetchedObjects  objectAtIndex:0]; else        return  nil; CD
  68. 68. [Person findByAttribute:@"age" withValue:@25]; MR
  69. 69. // Query to find all the persons store into the database NSArray *persons = [Person MR_findAll];   // Query to find all the persons store into the database order by their 'firstname' NSArray *personsSorted = [Person MR_findAllSortedBy:@"firstname" ascending:YES];   // Query to find all the persons store into the database which have 25 years old NSArray *personsWhoHave22 = [Person MR_findByAttribute:@"age" withValue:[NSNumber numberWithInt:25]];   // Query to find the first person store into the databe Person *person = [Person MR_findFirst]; MR
  70. 70. // Query to find all the persons store into the database NSArray *persons = [Person MR_findAll];   // Query to find all the persons store into the database order by their 'firstname' NSArray *personsSorted = [Person MR_findAllSortedBy:@"firstname" ascending:YES];   // Query to find all the persons store into the database which have 25 years old NSArray *personsWhoHave22 = [Person MR_findByAttribute:@"age" withValue:[NSNumber numberWithInt:25]];   // Query to find the first person store into the databe Person *person = [Person MR_findFirst]; MR
  71. 71. // Query to find all the persons store into the database NSArray *persons = [Person findAll];   // Query to find all the persons store into the database order by their 'firstname' NSArray *personsSorted = [Person findAllSortedBy:@"firstname" ascending:YES];   // Query to find all the persons store into the database which have 25 years old NSArray *personsWhoHave22 = [Person findByAttribute:@"age" withValue:[NSNumber numberWithInt:25]];   // Query to find the first person store into the databe Person *person = [Person findFirst]; MR
  72. 72. Background Op
  73. 73. [MagicalRecord  saveWithBlock:^(NSManagedObjectContext   *localContext)  {        Post  *post  =   [Post  createInContext:localContext];        //  photo  processing        //  update  post  from  photo  processing }  completion:^(BOOL  success,  NSError  *error)  {      //  This  is  called  when  data  done,        //  and  is  called  on  the  main  thread }]; MR
  74. 74. Mogenerator
  75. 75. Mogenerator Because Xcode sucks!
  76. 76. Mogenerator Because Xcode sucks! _User for machine User for human
  77. 77. Mogenerator Because Xcode sucks! _User for machine User for human + auto regen!
  78. 78. But the docs sucks too! It coves the basics, but I DO NEED to DIVE in! goo.gl/9fNe0z goo.gl/durEGR
  79. 79. Recap •You want to use Core Data •You want to use NSFetchResultsController •You want to use MagicalRecord •You want to use Mogenerator •YOP, setup of that is epic! •You want to use CocoaPods •YOP, docs for CoreData and MagicalRecord sucks LET the CoreData work for you!
  80. 80. For-Mobile http://srazy.info/for-mobile Pondělí, 24. 3. 2014  19:00 Jakub Hladík Automatic builds for iOS => Tomorrow! => AfterPUB included!
  81. 81. Tomáš Jukin @Inza www.juicymo.cz @JuicymoCZ
  82. 82. Tomáš Jukin @Inza www.juicymo.cz@JuicymoCZ goo.gl/jGLovj
  83. 83. Photo Credits All photos used are CC from Flickr http://www.flickr.com/photos/ 60256070@N05/8330184193/

×