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

CoreData - there is an ORM you can like!

CoreData - there is an ORM you can like!

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 (more at http://www.iconprague.com/detailni-program/#core-data-i-orm-muzete-mit-radi)

Tomas Jukin

March 23, 2014
Tweet

More Decks by Tomas Jukin

Other Decks in Programming

Transcript

  1. Core Data? -- It’s a big hairy mess! YES! but

    Why? Real problems are hard. Really?
  2. Core Data? -- It’s a big hairy mess! YES! but

    Why? Real problems are hard. Really? Really.
  3. Core Data? -- It’s a big hairy mess! YES! but

    Why? Real problems are hard. Really? Really. CoreData is hairy
  4. Core Data? -- It’s a big hairy mess! YES! but

    Why? Real problems are hard. Really? Really. CoreData is hairy because it ...
  5. 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!
  6. “Do you understand how to structure real-world data access for

    Mac and iOS applications better than Apple?”
  7. “Do you understand how to structure real-world data access for

    Mac and iOS applications better than Apple?” -- Nope.
  8. • 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?
  9. 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!
  10. ... all of that is TRUE for you Core Data

    is NOT for you. Otherwise you SHOULD use it.
  11. Core Data = Do not implement Do not test Do

    not optimize Data Stack code used by your app! Apple has already done that!
  12. Cocoa for Models Is UIButton easy? Is UITableView easy? Is

    Delegation Pattern easy? Is InterfaceBuilder and outlets easy?
  13. Cocoa for Models Is UIButton easy? Is UITableView easy? Is

    Delegation Pattern easy? Is InterfaceBuilder and outlets easy? NOPE!
  14. •Programmer naivity ➜ “My app isn’t complex enought” = I

    am too lazy to learn it Why NOT to use Core Data?
  15. •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?
  16. •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?
  17. •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?
  18. 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...
  19. OK, but when seriously NO? Update HUGE part of DB

    in one moment Working with lots of records ➜ RSS Reader app
  20. .sqlite App Schema App .sqlite Web Store NSManaged ObjectContext NSManaged

    ObjectContext NSManaged ObjectModel Persistent ObjectStore Persistent ObjectStore Persistent ObjectStore Persistent Store Coordinator
  21. .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
  22. // 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]; }
  23. // 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
  24. 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
  25. 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
  26. // 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
  27. // 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
  28. // 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
  29. [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
  30. But the docs sucks too! It coves the basics, but

    I DO NEED to DIVE in! goo.gl/9fNe0z goo.gl/durEGR
  31. 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!