$30 off During Our Annual Pro Sale. View Details »

High Performance Core Data

High Performance Core Data

http://highperformancecoredata.com/

Learn how to analyze, debug, and squeeze every last bit of performance out of Core Data. The standard Core Data implementation is very powerful and flexible but lacks performance. In this advanced session we will cover various performance analysis tools, model optimization, and various high performance concurrency models. This is an advanced discussion that assumes you have used Core Data before.

Matthew Morey

November 15, 2013
Tweet

More Decks by Matthew Morey

Other Decks in Technology

Transcript

  1. High Performance
    Core Data
    HighPerformanceCoreData.com
    MatthewMorey.com | @xzolian

    View Slide

  2. Agenda

    View Slide

  3. Managed Object
    Context
    Managed
    Object
    Managed
    Object
    Persistent Store
    Coordinator
    Persistent Store
    (SQLite, XML, ...)
    Model
    Main Queue

    View Slide

  4. Memory
    Speed
    Less More
    Slow Fast

    View Slide

  5. Memory
    Speed
    Less More
    Slow Fast

    View Slide

  6. Memory
    Speed
    Less More
    Slow Fast

    View Slide

  7. View Slide

  8. View Slide

  9. Tools

    View Slide

  10. #define TICK NSDate *startTime = [NSDate date]
    #define TOCK NSLog(@"Elapsed Time: %f",
    -[startTime timeIntervalSinceNow])

    View Slide

  11. #define TICK NSDate *startTime = [NSDate date]
    #define TOCK NSLog(@"Elapsed Time: %f",
    -[startTime timeIntervalSinceNow])
    ...
    TICK;
    [self methodYouWantToMeasure];
    TOCK;

    View Slide

  12. -com.apple.CoreData.SQLDebug [1,2,3]

    View Slide

  13. -com.apple.CoreData.SQLDebug [1,2,3]

    View Slide

  14. -com.apple.CoreData.SQLDebug [1,2,3]

    View Slide

  15. -com.apple.CoreData.SQLDebug [1,2,3]

    View Slide

  16. -com.apple.CoreData.SQLDebug [1,2,3]
    -com.apple.CoreData.SyntaxColoredLogging 1
    -com.apple.CoreData.MigrationDebug 1
    -com.apple.CoreData.SQLiteDebugSynchronous [0,1,2]
    -com.apple.CoreData.SQLiteIntegrityCheck [1]
    -com.apple.CoreData.ConcurrencyDebug [1,2,3]

    View Slide

  17. $ sqlite3

    View Slide

  18. $ sqlite3 UFO.sqlite
    sqlite> select * from sqlite_master;
    table|ZUFOSIGHTING|ZUFOSIGHTING|3|CREATE TABLE
    ZUFOSIGHTING ( Z_PK...VARCHAR )
    table|Z_PRIMARYKEY|Z_PRIMARYKEY|4|CREATE TABLE
    Z_PRIMARYKEY (Z_ENT...INTEGER)
    table|Z_METADATA|Z_METADATA|5|CREATE TABLE
    Z_METADATA (Z_VERSION...BLOB)

    View Slide

  19. sqlite> SELECT t0.ZSHAPE, COUNT( t0.ZSHAPE )
    FROM ZUFOSIGHTING t0 GROUP BY t0.ZSHAPE;
    changed|1
    changing|1546
    chevron|760
    cigar|1782
    circle|5271
    cone|265
    ...
    teardrop|595
    triangle|6082
    unknown|4490

    View Slide

  20. SQLite
    Professional
    Pony Debugger

    View Slide

  21. View Slide

  22. View Slide

  23. Tools
    •Macros
    •Launch Arguments
    •SQL
    •Instruments
    •Measure, Measure, Measure

    View Slide

  24. Fetching

    View Slide

  25. View Slide

  26. NSFetchRequest *fetchRequest =
    [NSFetchRequest fetchRequestWithEntityName:@"UFOSighting"];
    [fetchRequest setFetchBatchSize:20];

    View Slide

  27. View Slide

  28. View Slide

  29. NSFetchRequest *fetchRequest =
    [NSFetchRequest fetchRequestWithEntityName:@"UFOSighting"];
    NSArray *UFOSightingsArray =
    [self.managedObjectContext executeFetchRequest:fetchRequest
    error:&error];
    NSMutableDictionary *uniqueShapesDictionary =
    [NSMutableDictionary dictionary];
    for (UFOSighting *sighting in UFOSightingsArray) {
    ...
    // Count unique shape items
    ...
    }
    NSManagedObject

    View Slide

  30. NSFetchRequest *fetchRequest =
    [NSFetchRequest fetchRequestWithEntityName:@"UFOSighting"];
    [fetchRequest setResultType:NSDictionaryResultType];
    [fetchRequest setPropertiesToFetch:@"shape"];
    ...
    // Count unique shape items
    ...
    NSDictionaryResultType

    View Slide

  31. NSFetchRequest *fetchRequest =
    [NSFetchRequest fetchRequestWithEntityName:@"UFOSighting"];
    [fetchRequest setPredicate:
    [NSPredicate predicateWithFormat:
    @"shape == %@", @"sphere"]];
    NSUInteger sphereCount =
    [self.managedObjectContext countForFetchRequest:fetchRequest
    error:&error];
    ...
    // Repeat for each unique shape
    ...
    countForFetchRequest:error:

    View Slide

  32. NSFetchRequest *fetchRequest =
    [NSFetchRequest fetchRequestWithEntityName:@"UFOSighting"];
    NSExpressionDescription *expressionDescription =
    [[NSExpressionDescription alloc] init];
    [expressionDescription setName:@"count"];
    [expressionDescription setExpression:
    [NSExpression expressionForFunction:@"count:" arguments:
    @[[NSExpression expressionForKeyPath:@"shape"]]]];
    [fetchRequest setPropertiesToFetch:@[@"shape", expressionDescription]];
    [fetchRequest setPropertiesToGroupBy:@[@"shape"]];
    [fetchRequest setResultType:NSDictionaryResultType];
    NSExpression

    View Slide

  33. NSExpression
    NSFetchRequest *fetchRequest =
    [NSFetchRequest fetchRequestWithEntityName:@"UFOSighting"];
    NSExpressionDescription *expressionDescription =
    [[NSExpressionDescription alloc] init];
    [expressionDescription setName:@"count"];
    [expressionDescription setExpression:
    [NSExpression expressionForFunction:@"count:" arguments:
    @[[NSExpression expressionForKeyPath:@"shape"]]]];
    [fetchRequest setPropertiesToFetch:@[@"shape", expressionDescription]];
    [fetchRequest setPropertiesToGroupBy:@[@"shape"]];
    [fetchRequest setResultType:NSDictionaryResultType];

    View Slide

  34. View Slide

  35. Prefetch Required Relationships

    View Slide

  36. [fetchRequest
    setRelationshipKeyPathsForPrefetching:
    @[@"photo"]];

    View Slide

  37. Fetch in the background

    View Slide

  38. [backgroundContext performBlock:^{
    NSFetchRequest *fetchRequest = [NSFetchRequest
    fetchRequestWithEntityName:@"UFOSighting"];
    fetchRequest.resultType = NSManagedObjectIDResultType;
    NSArray *managedObjectIDs = [backgroundContext
    executeFetchRequest:fetchRequest
    error:nil];
    [mainQueueContext performBlock:^{
    for (NSManagedObjectID *managedObjectID in managedObjectIDs) {
    UFOSighting *UFOSighting = [mainQueueContext
    objectWithID:managedObjectID];
    //
    // Update UI on main queue
    //
    }
    }];
    }];

    View Slide

  39. [backgroundContext performBlock:^{
    NSFetchRequest *fetchRequest = [NSFetchRequest
    fetchRequestWithEntityName:@"UFOSighting"];
    fetchRequest.resultType = NSManagedObjectIDResultType;
    NSArray *managedObjectIDs = [backgroundContext
    executeFetchRequest:fetchRequest
    error:nil];
    [mainQueueContext performBlock:^{
    for (NSManagedObjectID *managedObjectID in managedObjectIDs) {
    UFOSighting *UFOSighting = [mainQueueContext
    objectWithID:managedObjectID];
    //
    // Update UI on main queue
    //
    }
    }];
    }];

    View Slide

  40. [backgroundContext performBlock:^{
    NSFetchRequest *fetchRequest = [NSFetchRequest
    fetchRequestWithEntityName:@"UFOSighting"];
    fetchRequest.resultType = NSManagedObjectIDResultType;
    NSArray *managedObjectIDs = [backgroundContext
    executeFetchRequest:fetchRequest
    error:nil];
    [mainQueueContext performBlock:^{
    for (NSManagedObjectID *managedObjectID in managedObjectIDs) {
    UFOSighting *UFOSighting = [mainQueueContext
    objectWithID:managedObjectID];
    //
    // Update UI on main queue
    //
    }
    }];
    }];

    View Slide

  41. [backgroundContext performBlock:^{
    NSFetchRequest *fetchRequest = [NSFetchRequest
    fetchRequestWithEntityName:@"UFOSighting"];
    fetchRequest.resultType = NSManagedObjectIDResultType;
    NSArray *managedObjectIDs = [backgroundContext
    executeFetchRequest:fetchRequest
    error:nil];
    [mainQueueContext performBlock:^{
    for (NSManagedObjectID *managedObjectID in managedObjectIDs) {
    UFOSighting *UFOSighting = [mainQueueContext
    objectWithID:managedObjectID];
    //
    // Update UI on main queue
    //
    }
    }];
    }];

    View Slide

  42. NSFetchRequest *request = [NSFetchRequest
    fetchRequestWithEntityName:”MyEntity”];
    NSAsynchronousFetchRequest *async = [[NSAsynchronousFetchRequest alloc]
    initWithFetchRequest:request completionBlock^(id result) {
    if (result.finalResult) {
    ...
    }
    }];
    [context performBlock: ^() {
    NSError *error = nil;
    asyncResult = [moc executeRequest:asyncRequest error:&blockError];
    }];
    iOS 8 | OS X Yosemite

    View Slide

  43. Fetching
    •Don’t fetch more than you need
    •Set a batch size
    •Let SQLite do the calculations
    •Prefetch required relationships
    •Fetch in the background

    View Slide

  44. Predicates

    View Slide

  45. Light Comparisons First

    View Slide

  46. [fetchRequest setPredicate:
    [NSPredicate predicateWithFormat:
    @"shape == %@ AND duration > %i", @"sphere", 30]];

    View Slide

  47. [fetchRequest setPredicate:
    [NSPredicate predicateWithFormat:
    @"shape == %@ AND duration > %i", @"sphere", 30]];
    [fetchRequest setPredicate:
    [NSPredicate predicateWithFormat:
    @"duration > %i AND shape == %@", 30, @"sphere"]];

    View Slide

  48. Be cautious with strings

    View Slide

  49. Predicate
    Costs
    Less More
    Beginswith
    Endswith
    Equality
    ==
    Contains
    Matches

    View Slide

  50. Predicate
    Costs
    Less More
    Beginswith
    Endswith
    Equality
    ==
    Contains
    Matches
    [cd] cost you even more

    View Slide

  51. Predicates
    •Do light (numerical) comparisons first
    •Beginswith/Endswith instead of Contains/Matches
    •Don’t use [cd]

    View Slide

  52. Searching

    View Slide

  53. Canonicalize String Properties

    View Slide

  54. Canonicalize String Properties
    Description canonicalizedDesc
    Green Mën green men
    BEAM beam
    Prόbë probe
    ABDUCTION abduction

    View Slide

  55. CFStringNormalize((CFMutableStringRef)result,
    kCFStringNormalizationFormD);
    CFStringFold((CFMutableStringRef)result,
    kCFCompareCaseInsensitive |
    kCFCompareDiacriticInsensitive |
    kCFCompareWidthInsensitive, NULL);

    View Slide

  56. Canonicalized Tokens

    View Slide

  57. View Slide

  58. View Slide

  59. componentsSeperatedByCharactersInSet

    View Slide

  60. Separate Stack

    View Slide

  61. Managed Object
    Context
    Persistent Store
    Coordinator
    Persistent Store
    (SQLite, XML, ...)
    Model
    Primary
    Managed Object
    Context
    Persistent Store
    Coordinator
    Persistent Store
    (SQLite, XML, ...)
    Model
    Search Tokens

    View Slide

  62. Managed Object
    Context
    Persistent Store
    Coordinator
    Persistent Store
    (SQLite, XML, ...)
    Model
    Primary
    Managed Object
    Context
    Persistent Store
    Coordinator
    Persistent Store
    (SQLite, XML, ...)
    Model
    Search Tokens
    URIRepresentation

    View Slide

  63. Hash of Tokens

    View Slide

  64. Searching
    •Canonicalize text properties
    •Use tokens
    •Separate persistence stack
    •Hash of tokens

    View Slide

  65. Data Model

    View Slide

  66. Don’t Overnormalize

    View Slide

  67. Use External Storage

    View Slide

  68. View Slide

  69. View Slide

  70. View Slide

  71. View Slide

  72. Data Model
    •Don’t overnormalize
    •Use external storage for large attributes
    •Large blobs as separate entity
    •Less data takes less time to fetch

    View Slide

  73. App Launch

    View Slide

  74. “Lots of Things”
    Problem

    View Slide

  75. NSBatchUpdateRequest *batchRequest = [NSBatchUpdateRequest batchUpdateRequestWithEntityName:
    [RSSItem entityName]];
    batchRequest.propertiesToUpdate =
    @{NSStringFromSelector(@selector(read)): [NSNumber numberWithBool:YES]};
    batchRequest.resultType = NSStatusOnlyResultType;
    batchRequest.predicate = [NSPredicate predicateWithFormat:@"..."];
    NSError *requestError;
    NSBatchUpdateResult *result = (NSBatchUpdateResult *)[self.managedObjectContext
    executeRequest:batchRequest error:&requestError];
    if (result == nil) {
    NSLog(@"Error: %@", [requestError localizedDescription]);
    } else {
    // Batch update succeeded
    }
    iOS 8 | OS X Yosemite

    View Slide

  76. Importing Data

    View Slide

  77. View Slide

  78. Main Queue vs Private Queue
    self.managedObjectContext =
    self.persistenceStack.managedObjectContext;
    [self.managedObjectContext performBlockAndWait:^{
    [self import];
    }];

    View Slide

  79. Main Queue vs Private Queue
    NSManagedObjectContext *privateManagedObjectContext =
    [[NSManagedObjectContext alloc]
    initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    [privateManagedObjectContext setPersistentStoreCoordinator:
    self.managedObjectContext.persistentStoreCoordinator];
    [privateManagedObjectContext performBlockAndWait:^{
    [self import];
    }];

    View Slide

  80. View Slide

  81. Typical Import Algorithm
    1) JSON to NSDictionary
    2) Find existing NSManagedObject
    3) Optionally, create new NSManagedObject
    4) Set attributes of new/updated NSManagedObject
    5) Repeat for every JSON item

    View Slide

  82. Typical Import Algorithm
    1) JSON to NSDictionary
    2) Find existing NSManagedObject
    3) Optionally, create new NSManagedObject
    4) Set attributes of new/updated NSManagedObject
    5) Repeat for every JSON item

    View Slide

  83. Efficient Import Algorithm
    1) Sort import objects by ID
    2) Execute a single fetch request for all matching IDs
    3) Iterate through both import and existing objects
    4) Update or create

    View Slide

  84. 1
    4
    2
    3
    ...
    New Data

    View Slide

  85. 1
    4
    2
    3
    ...
    New Data
    4
    1
    ...
    Existing Data

    View Slide

  86. 1
    4
    2
    3
    ...
    New Data
    4
    1
    ...
    Existing Data

    View Slide

  87. 1
    4
    2
    3
    ...
    New Data
    4
    1
    ...
    Existing Data

    View Slide

  88. 1
    4
    2
    3
    ...
    New Data
    4
    1
    ...
    Existing Data

    View Slide

  89. 1
    2
    3
    4
    ...
    New Data
    1
    4
    ...
    Existing Data
    Update

    View Slide

  90. 1
    2
    3
    4
    ...
    New Data
    1
    4
    ...
    Existing Data
    Update

    View Slide

  91. 1
    2
    3
    4
    ...
    New Data
    1
    4
    ...
    Existing Data
    Insert

    View Slide

  92. 1
    2
    3
    4
    ...
    New Data
    1
    4
    ...
    Existing Data
    Insert

    View Slide

  93. 2
    1
    2
    3
    4
    ...
    New Data
    1
    4
    ...
    Existing Data

    View Slide

  94. 2
    1
    2
    3
    4
    ...
    New Data
    1
    4
    ...
    Existing Data

    View Slide

  95. 1
    2
    3
    4
    ...
    New Data
    1
    4
    ...
    Existing Data
    2

    View Slide

  96. 1
    2
    3
    4
    ...
    New Data
    1
    4
    ...
    Existing Data
    2
    Insert

    View Slide

  97. 1
    2
    3
    4
    ...
    New Data
    1
    4
    ...
    Existing Data
    2
    Insert

    View Slide

  98. 3
    1
    2
    3
    4
    ...
    New Data
    1
    4
    ...
    Existing Data
    2

    View Slide

  99. 3
    1
    2
    3
    4
    ...
    New Data
    1
    4
    ...
    Existing Data
    2

    View Slide

  100. 1
    2
    3
    4
    ...
    New Data
    1
    4
    ...
    Existing Data
    2
    3
    Update

    View Slide

  101. 1
    2
    3
    4
    ...
    New Data
    1
    4
    ...
    Existing Data
    2
    3
    Update

    View Slide

  102. View Slide

  103. Efficient Import Algorithm With Batching
    1) Sort import objects by ID
    2) Execute multiple fetch request for matching IDs
    - Iterate through both import and existing objects
    - Update or create
    3) Save Batch

    View Slide

  104. // Grab sorted persisted managed objects, based on the batch
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]
    initWithEntityName:@"UFOSighting"];
    NSPredicate *fetchPredicate = [NSPredicate predicateWithFormat:
    @"%K IN %@", @"GUID", jsonBatchGUIDArray];

    View Slide

  105. // Grab sorted persisted managed objects, based on the batch
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]
    initWithEntityName:@"UFOSighting"];
    NSPredicate *fetchPredicate = [NSPredicate predicateWithFormat:
    @"%K IN %@", @"GUID", jsonBatchGUIDArray];

    View Slide

  106. Pre-Populated SQLite
    File in App Bundle

    View Slide

  107. Download Pre-Populated
    SQLite File

    View Slide

  108. Importing Data
    •Do import work on private queues
    •Use efficient find-or-create algorithm
    •Work in batches to keep memory low
    •Use pre-populated SQLite file

    View Slide

  109. Memory

    View Slide

  110. [context refreshObject:UFOSightingManagedObject
    mergeChanges:NO];

    View Slide

  111. [context reset];

    View Slide

  112. Concurrency
    Models

    View Slide

  113. Managed Object
    Context
    Managed
    Object
    Managed
    Object
    Persistent Store
    Coordinator
    Persistent Store
    (SQLite, XML, ...)
    Model
    Main Queue

    View Slide

  114. Managed Object
    Context
    Managed
    Object
    Managed
    Object
    Persistent Store
    Coordinator
    Persistent Store
    (SQLite, XML, ...)
    Model
    Main Queue

    View Slide

  115. Managed Object
    Context
    Managed
    Object
    Managed
    Object
    Persistent Store
    Coordinator
    Persistent Store
    (SQLite, XML, ...)
    Model
    Main Queue

    View Slide

  116. Managed Object
    Context
    Persistent Store
    Coordinator
    Persistent Store
    (SQLite, XML, ...)
    Model
    Managed Object
    Context
    Main Queue Private Queue

    View Slide

  117. Managed Object
    Context
    Persistent Store
    Coordinator
    Persistent Store
    (SQLite, XML, ...)
    Model
    Managed Object
    Context
    Main Queue Private Queue

    View Slide

  118. Managed Object
    Context
    Persistent Store
    Coordinator
    Persistent Store
    (SQLite, XML, ...)
    Model
    Managed Object
    Context
    Main Queue Private Queue

    View Slide

  119. Managed Object
    Context
    Persistent Store
    Coordinator
    Persistent Store
    (SQLite, XML, ...)
    Model
    Managed Object
    Context
    Main Queue Private Queue
    Context Did Save
    Notification
    Merge Changes
    From Notification

    View Slide

  120. Managed Object
    Context
    Persistent Store
    Coordinator
    Persistent Store
    (SQLite, XML, ...)
    Model
    Managed Object
    Context
    Main Queue Private Queue
    Context Did Save
    Notification
    Merge Changes
    From Notification

    View Slide

  121. Managed Object
    Context
    Persistent Store
    Coordinator
    Persistent Store
    (SQLite, XML, ...)
    Model
    Managed Object
    Context
    Main Queue Private Queue
    Context Did Save
    Notification
    Refetch and
    Reload

    View Slide

  122. Persistent Store
    Coordinator
    Persistent Store
    Model
    Main Queue
    Managed Object
    Context
    Managed Object
    Context
    Private Queue

    View Slide

  123. Persistent Store
    Coordinator
    Persistent Store
    Model
    Main Queue
    Managed Object
    Context
    Managed Object
    Context
    Private Queue
    UI Work

    View Slide

  124. Persistent Store
    Coordinator
    Persistent Store
    Model
    Main Queue
    Managed Object
    Context
    Managed Object
    Context
    Private Queue
    UI Work
    Persisting to
    Disk

    View Slide

  125. Persistent Store
    Coordinator
    Persistent Store
    Model
    Main Queue
    Managed Object
    Context
    Managed Object
    Context
    Private Queue
    UI Work
    Persisting to
    Disk

    View Slide

  126. Persistent Store
    Coordinator
    Persistent Store
    Model
    Main Queue
    Managed Object
    Context
    Managed Object
    Context
    Private Queue
    UI Work
    Persisting to
    Disk

    View Slide

  127. Persistent Store
    Coordinator
    Persistent Store
    Model
    Main Queue
    Managed Object
    Context
    Managed Object
    Context
    Private Queue
    UI Work
    Persisting to
    Disk

    View Slide

  128. Persistent Store
    Coordinator
    Persistent Store
    Model
    Main Queue
    Managed Object
    Context
    Managed Object
    Context
    Private Queue
    UI Work
    Persisting to
    Disk

    View Slide

  129. Persistent Store
    Coordinator
    Persistent Store
    Model
    Main Queue
    Managed Object
    Context
    Private Queue
    Managed Object
    Context
    Managed Object
    Context
    Private Queue

    View Slide

  130. Persistent Store
    Coordinator
    Persistent Store
    Model
    Main Queue
    Managed Object
    Context
    Private Queue
    Managed Object
    Context
    Managed Object
    Context
    Private Queue
    Background
    Updates

    View Slide

  131. Persistent Store
    Coordinator
    Persistent Store
    Model
    Main Queue
    Managed Object
    Context
    Private Queue
    Managed Object
    Context
    Managed Object
    Context
    Private Queue
    Background
    Updates
    UI Work

    View Slide

  132. Persistent Store
    Coordinator
    Persistent Store
    Model
    Main Queue
    Managed Object
    Context
    Private Queue
    Managed Object
    Context
    Managed Object
    Context
    Private Queue
    Background
    Updates
    UI Work
    Persisting to
    Disk

    View Slide

  133. Persistent Store
    Coordinator
    Persistent Store
    Model
    Main Queue
    Managed Object
    Context
    Private Queue
    Managed Object
    Context
    Managed Object
    Context
    Private Queue
    Background
    Updates
    UI Work
    Persisting to
    Disk

    View Slide

  134. Persistent Store
    Coordinator
    Persistent Store
    Model
    Main Queue
    Managed Object
    Context
    Private Queue
    Managed Object
    Context
    Managed Object
    Context
    Private Queue
    Background
    Updates
    UI Work
    Persisting to
    Disk

    View Slide

  135. Persistent Store
    Coordinator
    Persistent Store
    Model
    Main Queue
    Managed Object
    Context
    Private Queue
    Managed Object
    Context
    Managed Object
    Context
    Private Queue
    Background
    Updates
    UI Work
    Persisting to
    Disk
    __block NSManagedObjectContext *temporaryContext = self.workerObjectContext;
    __block NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
    __block NSManagedObjectContext *writerObjectContext = self.writerManagedObjectContext;
    [temporaryContext performBlock:^{
    NSError *error = nil;
    if (![temporaryContext save:&error]) {
    // TODO: Handle error
    }
    [managedObjectContext performBlock:^{
    NSError *error = nil;
    if (![managedObjectContext save:&error]) {
    // TODO: Handle error
    }
    [writerObjectContext performBlock:^{
    NSError *error = nil;
    if (![writerObjectContext save:&error]) {
    // TODO: Handle error
    }
    // Success!!!
    }]; // writerObjectContext
    }]; // managedObjectContext
    }]; // temporaryContext

    View Slide

  136. View Slide

  137. Managed Object
    Context
    Persistent Store
    Coordinator
    Persistent Store
    (SQLite, XML, ...)
    Model
    Managed Object
    Context
    Main Queue Private Queue
    Persistent Store
    Coordinator
    Model

    View Slide

  138. Managed Object
    Context
    Persistent Store
    Coordinator
    Persistent Store
    (SQLite, XML, ...)
    Model
    Managed Object
    Context
    Main Queue Private Queue
    Persistent Store
    Coordinator
    Model

    View Slide

  139. Managed Object
    Context
    Persistent Store
    Coordinator
    Persistent Store
    (SQLite, XML, ...)
    Model
    Managed Object
    Context
    Main Queue Private Queue
    Persistent Store
    Coordinator
    Model

    View Slide

  140. Managed Object
    Context
    Persistent Store
    Coordinator
    Persistent Store
    (SQLite, XML, ...)
    Model
    Managed Object
    Context
    Main Queue Private Queue
    Persistent Store
    Coordinator
    Model

    View Slide

  141. Managed Object
    Context
    Persistent Store
    Coordinator
    Persistent Store
    (SQLite, XML, ...)
    Model
    Managed Object
    Context
    Main Queue Private Queue
    Persistent Store
    Coordinator
    Model
    Context Did Save
    Notification

    View Slide

  142. Managed Object
    Context
    Persistent Store
    Coordinator
    Persistent Store
    (SQLite, XML, ...)
    Model
    Managed Object
    Context
    Main Queue Private Queue
    Persistent Store
    Coordinator
    Model
    Context Did Save
    Notification
    Merge Changes
    From Notification

    View Slide

  143. Managed Object
    Context
    Persistent Store
    Coordinator
    Persistent Store
    (SQLite, XML, ...)
    Model
    Managed Object
    Context
    Main Queue Private Queue
    Persistent Store
    Coordinator
    Model
    Context Did Save
    Notification
    Merge Changes
    From Notification

    View Slide

  144. Managed Object
    Context
    Persistent Store
    Coordinator
    Persistent Store
    (SQLite, XML, ...)
    Model
    Managed Object
    Context
    Main Queue Private Queue
    Persistent Store
    Coordinator
    Model
    Context Did Save
    Notification
    Refetch and
    Reload

    View Slide

  145. View Slide

  146. Managed Object
    Context
    Persistent Store
    Coordinator
    Persistent Store
    (SQLite, XML, ...)
    Model
    Managed Object
    Context
    Main Queue Private Queue
    Persistent Store
    Coordinator
    Model
    Context Did Save
    Notification
    Refetch and
    Reload
    •Cannot pass objects between persistent store
    coordinators
    •Cannot pass objectIDs between persistent store
    coordinators
    •You can use URIRepresentation
    •You can use
    mergeChangesFromContextDidSaveNotification

    View Slide

  147. TLDR

    View Slide

  148. Managed Object
    Context
    Persistent Store
    Coordinator
    Persistent Store
    (SQLite, XML, ...)
    Model
    Managed Object
    Context
    Main Queue Private Queue
    Context Did Save
    Notification
    Refetch and
    Reload

    View Slide

  149. Concurrency Models
    •Use the simplest model that meets your needs
    •Update main context after large imports have
    completed

    View Slide

  150. Bang
    Head
    Here

    View Slide

  151. In general...
    •Use the tools, and measure, measure, measure
    •Don’t load more than you need to
    •Don’t use [cd]
    •Be smart with your data model
    •Import on a private queue in batches
    •Pick the correct (but simplest) concurrency model

    View Slide

  152. Questions?
    HighPerformanceCoreData.com
    MatthewMorey.com | @xzolian
    BuoyExplorer.com - Marine Conditions App
    WristPresenter.com - Presentation App
    ChaiOne.com - Hiring remote iOS engineers

    View Slide