Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Core Datawith multiple managed   object contexts                        Photo by Free-Photo-Gallery.org
Core Datawith multiple managed   object contexts                        Photo by Free-Photo-Gallery.org
Matt(hew) Morey                   Senior Developer at ChaiONE                                        Traveler             ...
Agenda1)Core Data Basics2)Concurrency Problems3)Concurrency Solutions
Agenda1)Core Data Basics2)Concurrency Problems3)Concurrency Solutions
Basics
Basics                          App                    NSManagedObject                NSManagedObjectContextNSPersistentSt...
Basics                          App                    NSManagedObject                NSManagedObjectContextNSPersistentSt...
Managed Object Model
Managed Object Model
Managed Object Model- (NSManagedObjectModel *)managedObjectModel{    if (_managedObjectModel != nil) {        return _mana...
Persistent Store Coordinator
Persistent STore Coordinator- (NSPersistentStoreCoordinator *)persistentStoreCoordinator{    if (_persistentStoreCoordinat...
Persistent STore Coordinator- (NSPersistentStoreCoordinator *)persistentStoreCoordinator{    if (_persistentStoreCoordinat...
Managed Object Context
Managed Object Context- (NSManagedObjectContext *)managedObjectContext{    if (_managedObjectContext != nil) {        retu...
Single Context
Single Context
Single Context                Code Examplehttps://github.com/mmorey/CoreDataMultiContext/tree/blocking
Agenda1)Core Data Basics2)Concurrency Problems3)Concurrency Solutions
Problems‣Core Data Managed Objects are not thread safe ‣Must pass Object IDs to use across threads‣Objects are locked for ...
Agenda1)Core Data Basics2)Concurrency Problems3)Concurrency Solutions
Traditional Multi-ContextPre-iOS 5: Thread Confinement‣Single NSMangedObjectContext per thread‣Manual notifications, mergi...
Traditional Multi-Context
Traditional Multi-Context- (void)loadData{    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,...
Traditional Multi-Context- (void)loadData{    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,...
Traditional Multi-Context- (void)loadData{    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,...
Traditional Multi-Context- (void)contextDidSave:(NSNotification *)notification {    dispatch_async(dispatch_get_main_queue...
Traditional Multi-Context- (void)contextDidSave:(NSNotification *)notification {    dispatch_async(dispatch_get_main_queue...
Traditional Multi-Context                      Code Examplehttps://github.com/mmorey/CoreDataMultiContext/tree/notificatio...
Parent Child Context≥ iOS 5: Parent Child Contexts‣Grand Central Dispatch private dispatch queues‣Threading managed for yo...
Concurrency TypesNSManagedObjectContext *temporaryContext = [[NSManagedObjectContext alloc]                               ...
Parent Child Context
Parent Child Context  PSC                  PSC
Parent Child Context__block NSManagedObjectContext *managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplicati...
Parent Child Context__block NSManagedObjectContext *managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplicati...
Parent Child Context__block NSManagedObjectContext *managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplicati...
Parent Child Context__block NSManagedObjectContext *managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplicati...
Basics                          App                    NSManagedObject                NSManagedObjectContextNSPersistentSt...
Async Saving - Parent Child Context
Async Saving - Parent Child Context// Child context- (NSManagedObjectContext *)managedObjectContext{    if (_managedObject...
Async Saving - Parent Child Context// Child context- (NSManagedObjectContext *)managedObjectContext{    if (_managedObject...
Async Saving - Parent Child Context// Child context- (NSManagedObjectContext *)managedObjectContext{    if (_managedObject...
Parent Child Context__block NSManagedObjectContext *writerObjectContext = [(AppDelegate *)[[UIApplication sharedApplicatio...
Parent Child Context__block NSManagedObjectContext *writerObjectContext = [(AppDelegate *)[[UIApplication sharedApplicatio...
Asynchronous Saving - Parent Child Context                         Code Example      https://github.com/mmorey/CoreDataMul...
Still Blocking?
Still Blocking?Small and frequent saves during import
Still Blocking?Wait for opportunity when user won’t notice
Still Blocking?- (void)setStalenessInterval:(NSTimeInterval)expiration
Still Blocking?           NSFetchedResultsController *aFetchedResultsController =    [[NSFetchedResultsController alloc] i...
Still Blocking? For VERY LARGE amounts of data it may be  better to generate the SQLite file on theserver, download it asy...
References                                       Nested MOC Release Notes:      http://developer.apple.com/library/mac/#re...
Thanks!              Questions? Get in Touch.                        Twitter: @xzolian                        App.net: @mo...
Upcoming SlideShare
Loading in …5
×

Core Data with multiple managed object contexts

31,938 views

Published on

When using Core Data for persisting app data multiple managed object contexts (MOC) are often required to avoid blocking UI. Typically you would create a background MOC and listen for changes on the main MOC, merging changes as necessary. With iOS 5, MOCs now have parent context and the ability to set concurrency types. These new features greatly simplify dealing with Core Data on background queues. During this presentation Matt will cover the pros and cons of this new method of dealing with Core Data.

Published in: Technology

Core Data with multiple managed object contexts

  1. 1. Core Datawith multiple managed object contexts Photo by Free-Photo-Gallery.org
  2. 2. Core Datawith multiple managed object contexts Photo by Free-Photo-Gallery.org
  3. 3. Matt(hew) Morey Senior Developer at ChaiONE Traveler Boardsport Junkie matthewmorey.com | @xzolian
  4. 4. Agenda1)Core Data Basics2)Concurrency Problems3)Concurrency Solutions
  5. 5. Agenda1)Core Data Basics2)Concurrency Problems3)Concurrency Solutions
  6. 6. Basics
  7. 7. Basics App NSManagedObject NSManagedObjectContextNSPersistentStoreCoordinator NSManagedObjectModel NSPersistentStore SQLite XML Binary In Memory Custom
  8. 8. Basics App NSManagedObject NSManagedObjectContextNSPersistentStoreCoordinator NSManagedObjectModel NSPersistentStore SQLite XML Binary In Memory Custom
  9. 9. Managed Object Model
  10. 10. Managed Object Model
  11. 11. Managed Object Model- (NSManagedObjectModel *)managedObjectModel{ if (_managedObjectModel != nil) { return _managedObjectModel; } NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"core-data" withExtension:@"momd"]; _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; return _managedObjectModel;}
  12. 12. Persistent Store Coordinator
  13. 13. Persistent STore Coordinator- (NSPersistentStoreCoordinator *)persistentStoreCoordinator{ if (_persistentStoreCoordinator != nil) { return _persistentStoreCoordinator; } NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"core-data.sqlite"]; NSError *error = nil; _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) { /* Replace this implementation with code to handle the error appropriately. ... */ NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } return _persistentStoreCoordinator;}
  14. 14. Persistent STore Coordinator- (NSPersistentStoreCoordinator *)persistentStoreCoordinator{ if (_persistentStoreCoordinator != nil) { return _persistentStoreCoordinator; } NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"core-data.sqlite"]; NSError *error = nil; _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) { /* Replace this implementation with code to handle the error appropriately. ... */ NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } return _persistentStoreCoordinator;}
  15. 15. Managed Object Context
  16. 16. Managed Object Context- (NSManagedObjectContext *)managedObjectContext{ if (_managedObjectContext != nil) { return _managedObjectContext; } NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; if (coordinator != nil) { _managedObjectContext = [[NSManagedObjectContext alloc] init]; [_managedObjectContext setPersistentStoreCoordinator:coordinator]; } return _managedObjectContext;}
  17. 17. Single Context
  18. 18. Single Context
  19. 19. Single Context Code Examplehttps://github.com/mmorey/CoreDataMultiContext/tree/blocking
  20. 20. Agenda1)Core Data Basics2)Concurrency Problems3)Concurrency Solutions
  21. 21. Problems‣Core Data Managed Objects are not thread safe ‣Must pass Object IDs to use across threads‣Objects are locked for all operations including read ‣Objects that feed the UI must be fetched on the main thread
  22. 22. Agenda1)Core Data Basics2)Concurrency Problems3)Concurrency Solutions
  23. 23. Traditional Multi-ContextPre-iOS 5: Thread Confinement‣Single NSMangedObjectContext per thread‣Manual notifications, merging, and saving‣Fairly easy to understand, but harder to manage
  24. 24. Traditional Multi-Context
  25. 25. Traditional Multi-Context- (void)loadData{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ // Create temp context NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init]; [context setPersistentStoreCoordinator:[(AppDelegate *)[[UIApplication sharedApplication] delegate] persistentStoreCoordinator]]; // // Do lots of async work here // // Save the context. error = nil; if (![context save:&error]) { // Replace this implementation with code to handle the error appropriately. abort(); } });}// Register for save notification in ViewDidLoad[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextDidSave:) name:NSManagedObjectContextDidSaveNotification object:context];
  26. 26. Traditional Multi-Context- (void)loadData{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ // Create temp context NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init]; [context setPersistentStoreCoordinator:[(AppDelegate *)[[UIApplication sharedApplication] delegate] persistentStoreCoordinator]]; // // Do lots of async work here // // Save the context. error = nil; if (![context save:&error]) { // Replace this implementation with code to handle the error appropriately. abort(); } });}// Register for save notification in ViewDidLoad[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextDidSave:) name:NSManagedObjectContextDidSaveNotification object:context];
  27. 27. Traditional Multi-Context- (void)loadData{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ // Create temp context NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init]; [context setPersistentStoreCoordinator:[(AppDelegate *)[[UIApplication sharedApplication] delegate] persistentStoreCoordinator]]; // // Do lots of async work here // // Save the context. error = nil; if (![context save:&error]) { // Replace this implementation with code to handle the error appropriately. abort(); } });}// Register for save notification in ViewDidLoad[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextDidSave:) name:NSManagedObjectContextDidSaveNotification object:context];
  28. 28. Traditional Multi-Context- (void)contextDidSave:(NSNotification *)notification { dispatch_async(dispatch_get_main_queue(), ^{ NSManagedObjectContext *mainContext = [self.fetchedResultsController managedObjectContext]; [mainContext mergeChangesFromContextDidSaveNotification:notification]; });}// Or- (void)contextDidSave:(NSNotification *)notification { [self.managedObjectContext performSelectorOnMainThread: @selector(mergeChangesFromContextDidSaveNotification:) withObject:notification waitUntilDone:NO];}
  29. 29. Traditional Multi-Context- (void)contextDidSave:(NSNotification *)notification { dispatch_async(dispatch_get_main_queue(), ^{ NSManagedObjectContext *mainContext = [self.fetchedResultsController managedObjectContext]; [mainContext mergeChangesFromContextDidSaveNotification:notification]; });}// Or- (void)contextDidSave:(NSNotification *)notification { [self.managedObjectContext performSelectorOnMainThread: @selector(mergeChangesFromContextDidSaveNotification:) withObject:notification waitUntilDone:NO];}
  30. 30. Traditional Multi-Context Code Examplehttps://github.com/mmorey/CoreDataMultiContext/tree/notification-context
  31. 31. Parent Child Context≥ iOS 5: Parent Child Contexts‣Grand Central Dispatch private dispatch queues‣Threading managed for you, no manual synchronization required‣Less complicated and more flexible than pre-iOS 5 method‣Context can and should be nested
  32. 32. Concurrency TypesNSManagedObjectContext *temporaryContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; ‣NSConfinementConcurrencyType ‣Separate contexts for each thread ‣Default, Legacy option ‣NSPrivateQueueConcurrencyType ‣MOC maintains private serialized queue ‣Can be created from any other thread ‣Idle queues are more efficient than extra threads ‣NSMainQueueConcurrencyType ‣Similar to private queue but on the main queue
  33. 33. Parent Child Context
  34. 34. Parent Child Context PSC PSC
  35. 35. Parent Child Context__block NSManagedObjectContext *managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];NSManagedObjectContext *temporaryContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];temporaryContext.parentContext = managedObjectContext;[temporaryContext performBlock:^{ // // Do lots of async work here // // Save the context. NSError *error = nil; if (![temporaryContext save:&error]) {abort();} [managedObjectContext performBlock:^{ // Save the context. NSError *error = nil; if (![managedObjectContext save:&error]) {abort();} }]; // main}]; // temp context
  36. 36. Parent Child Context__block NSManagedObjectContext *managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];NSManagedObjectContext *temporaryContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];temporaryContext.parentContext = managedObjectContext;[temporaryContext performBlock:^{ // // Do lots of async work here // // Save the context. NSError *error = nil; if (![temporaryContext save:&error]) {abort();} [managedObjectContext performBlock:^{ // Save the context. NSError *error = nil; if (![managedObjectContext save:&error]) {abort();} }]; // main}]; // temp context
  37. 37. Parent Child Context__block NSManagedObjectContext *managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];NSManagedObjectContext *temporaryContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];temporaryContext.parentContext = managedObjectContext;[temporaryContext performBlock:^{ Private Queue save // // Do lots of async work here // propagates up to parent // Save the context. NSError *error = nil; if (![temporaryContext save:&error]) {abort();} [managedObjectContext performBlock:^{ // Save the context. NSError *error = nil; if (![managedObjectContext save:&error]) {abort();} }]; // main}]; // temp context
  38. 38. Parent Child Context__block NSManagedObjectContext *managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];NSManagedObjectContext *temporaryContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];temporaryContext.parentContext = managedObjectContext;[temporaryContext performBlock:^{ Save to disc still locks PS // which will block the UI during // Do lots of async work here // read operations // Save the context. NSError *error = nil; if (![temporaryContext save:&error]) {abort();} [managedObjectContext performBlock:^{ // Save the context. NSError *error = nil; if (![managedObjectContext save:&error]) {abort();} }]; // main}]; // temp context
  39. 39. Basics App NSManagedObject NSManagedObjectContextNSPersistentStoreCoordinator NSManagedObjectModel NSPersistentStore SQLite XML Binary In Memory Custom
  40. 40. Async Saving - Parent Child Context
  41. 41. Async Saving - Parent Child Context// Child context- (NSManagedObjectContext *)managedObjectContext{ if (_managedObjectContext != nil) { return _managedObjectContext; } _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; _managedObjectContext.parentContext = [self writerManagedObjectContext]; return _managedObjectContext;}// Parent context- (NSManagedObjectContext *)writerManagedObjectContext{ if (_writerManagedObjectContext != nil) { return _writerManagedObjectContext; } NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; if (coordinator != nil) { _writerManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType: NSPrivateQueueConcurrencyType]; [_writerManagedObjectContext setPersistentStoreCoordinator:coordinator]; } return _writerManagedObjectContext;}
  42. 42. Async Saving - Parent Child Context// Child context- (NSManagedObjectContext *)managedObjectContext{ if (_managedObjectContext != nil) { return _managedObjectContext; } _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; _managedObjectContext.parentContext = [self writerManagedObjectContext]; return _managedObjectContext;}// Parent context- (NSManagedObjectContext *)writerManagedObjectContext{ if (_writerManagedObjectContext != nil) { return _writerManagedObjectContext; } NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; if (coordinator != nil) { _writerManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType: NSPrivateQueueConcurrencyType]; [_writerManagedObjectContext setPersistentStoreCoordinator:coordinator]; } return _writerManagedObjectContext;}
  43. 43. Async Saving - Parent Child Context// Child context- (NSManagedObjectContext *)managedObjectContext{ if (_managedObjectContext != nil) { return _managedObjectContext; } _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; _managedObjectContext.parentContext = [self writerManagedObjectContext]; return _managedObjectContext;}// Parent context- (NSManagedObjectContext *)writerManagedObjectContext{ if (_writerManagedObjectContext != nil) { return _writerManagedObjectContext; } NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; if (coordinator != nil) { _writerManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType: NSPrivateQueueConcurrencyType]; [_writerManagedObjectContext setPersistentStoreCoordinator:coordinator]; } return _writerManagedObjectContext;}
  44. 44. Parent Child Context__block NSManagedObjectContext *writerObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] writerManagedObjectContext];__block NSManagedObjectContext *managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];__block NSManagedObjectContext *temporaryContext = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSPrivateQueueConcurrencyType];temporaryContext.parentContext = managedObjectContext;[temporaryContext performBlock:^{ // // Do lots of async work here // [temporaryContext save:&error]; {abort();} // Save the context. [managedObjectContext performBlock:^{ [managedObjectContext save:&error]; {abort();} // Save the context. [writerObjectContext performBlock:^{ [writerObjectContext save:&error]; {abort();} // Save the context. }]; // writer }]; // main}]; // temp context
  45. 45. Parent Child Context__block NSManagedObjectContext *writerObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] writerManagedObjectContext];__block NSManagedObjectContext *managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];__block NSManagedObjectContext *temporaryContext = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSPrivateQueueConcurrencyType];temporaryContext.parentContext = managedObjectContext;[temporaryContext performBlock:^{ NSPrivateQueueConcurrencyType // // Do lots of async work here // NSMainQueueConcurrency [temporaryContext save:&error]; {abort();} // Save the context. [managedObjectContext performBlock:^{ [managedObjectContext save:&error]; {abort();} // Save the context. [writerObjectContext performBlock:^{ [writerObjectContext save:&error]; {abort();} // Save the context. }]; // writer }]; // main}]; // temp context
  46. 46. Asynchronous Saving - Parent Child Context Code Example https://github.com/mmorey/CoreDataMultiContext/tree/parent-context
  47. 47. Still Blocking?
  48. 48. Still Blocking?Small and frequent saves during import
  49. 49. Still Blocking?Wait for opportunity when user won’t notice
  50. 50. Still Blocking?- (void)setStalenessInterval:(NSTimeInterval)expiration
  51. 51. Still Blocking? NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequestmanagedObjectContext:self.managedObjectContext sectionNameKeyPath:@"sections" cacheName:@"default-cache"];
  52. 52. Still Blocking? For VERY LARGE amounts of data it may be better to generate the SQLite file on theserver, download it asynchronously, and set it up as an additional persistent store.
  53. 53. References Nested MOC Release Notes: http://developer.apple.com/library/mac/#releasenotes/DataManagement/RN-CoreData/index.html Core Data Programming Guide:http://developer.apple.com/library/mac/#documentation/cocoa/Conceptual/CoreData/cdProgrammingGuide.html Cocoanetics Blog: http://www.cocoanetics.com/2012/07/multi-context-coredata/ http://www.cocoanetics.com/2013/02/zarra-on-locking/
  54. 54. Thanks! Questions? Get in Touch. Twitter: @xzolian App.net: @morey Email: matt@matthewmorey.com URL: http://matthewmorey.com

×