High Performance Core Data

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

description

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.

Transcript of High Performance Core Data

Page 1: High Performance Core Data

High PerformanceCore Data

HighPerformanceCoreData.com

MatthewMorey.com | @xzolian

Page 2: High Performance Core Data
Page 4: High Performance Core Data

Agenda

Page 5: High Performance Core Data

Managed ObjectContext

ManagedObject

ManagedObject

Persistent StoreCoordinator

Persistent Store(SQLite, XML, ...)

Model

Main Queue

Page 6: High Performance Core Data

Memory

Speed

Less More

Slow Faster

Page 7: High Performance Core Data

Memory

Speed

Less More

Slow Faster

Page 8: High Performance Core Data

Memory

Speed

Less More

Slow Faster

Page 9: High Performance Core Data
Page 10: High Performance Core Data

Tools

Page 11: High Performance Core Data

#define TICK NSDate *startTime = [NSDate date]

#define TOCK NSLog(@"Elapsed Time: %f", -[startTime timeIntervalSinceNow])

Page 12: High Performance Core Data

#define TICK NSDate *startTime = [NSDate date]

#define TOCK NSLog(@"Elapsed Time: %f", -[startTime timeIntervalSinceNow])

...

TICK;[self methodYouWantToMeasure];TOCK;

Page 13: High Performance Core Data

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

Page 14: High Performance Core Data

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

Page 15: High Performance Core Data

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

Page 16: High Performance Core Data

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

Page 17: High Performance Core Data

-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.ThreadingDebug [1,2,3]

Page 18: High Performance Core Data

$ sqlite3

Page 19: High Performance Core Data

$ 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)

Page 20: High Performance Core Data

sqlite> SELECT t0.ZSHAPE, COUNT( t0.ZSHAPE ) FROM ZUFOSIGHTING t0 GROUP BY t0.ZSHAPE;

changed|1changing|1546chevron|760cigar|1782circle|5271cone|265...teardrop|595triangle|6082unknown|4490

Page 21: High Performance Core Data

Pony Debugger

Page 22: High Performance Core Data
Page 23: High Performance Core Data

SQLiteProfessional

Page 24: High Performance Core Data
Page 25: High Performance Core Data
Page 26: High Performance Core Data
Page 27: High Performance Core Data
Page 28: High Performance Core Data
Page 29: High Performance Core Data
Page 30: High Performance Core Data

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

Page 31: High Performance Core Data

Fetching

Page 32: High Performance Core Data
Page 33: High Performance Core Data

NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"UFOSighting"];

[fetchRequest setFetchBatchSize:20];

Page 34: High Performance Core Data
Page 35: High Performance Core Data
Page 36: High Performance Core Data

NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"UFOSighting"];

NSArray *UFOSightingsArray = [self.managedObjectContext executeFetchRequest:fetchRequest error:NULL]; NSMutableDictionary *uniqueShapesDictionary = [NSMutableDictionary dictionary];

for (UFOSighting *sighting in UFOSightingsArray) { ... // Count unique shape items ...}

NSManagedObject

Page 37: High Performance Core Data

NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"UFOSighting"];

[fetchRequest setResultType:NSDictionaryResultType];[fetchRequest setPropertiesToFetch:@"shape"];

NSDictionaryResultType

Page 38: High Performance Core Data

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

Page 39: High Performance Core Data
Page 40: High Performance Core Data

Prefetch Required Relationships

Page 41: High Performance Core Data

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

Page 42: High Performance Core Data

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

Page 43: High Performance Core Data

Predicates

Page 44: High Performance Core Data

Light Comparisons First

Page 45: High Performance Core Data

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

Page 46: High Performance Core Data

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

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

Page 47: High Performance Core Data

Be Cautions with Strings

Page 48: High Performance Core Data

PredicateCosts

Less More

BeginswithEndswith

Equality==

Contains

Matches

Page 49: High Performance Core Data

PredicateCosts

Less More

BeginswithEndswith

Equality==

Contains

Matches

[cd] cost you even more

Page 50: High Performance Core Data

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

Page 51: High Performance Core Data

Searching

Page 52: High Performance Core Data

Canonicalize String Properties

Page 53: High Performance Core Data

Canonicalize String Properties

Description canonicalizedDesc

Green Mën green men

BEAM beam

Prόbë probe

ABDUCTION abduction

Page 54: High Performance Core Data

- (void)setDesc:(NSString *)desc { if (_desc != desc) { _desc = desc; [self updateCanonicalizedDesc:desc]; }}

- (void)updateCanonicalizedDesc:(NSString *)desc { NSMutableString *result = [NSMutableString stringWithString:desc]; CFStringNormalize((CFMutableStringRef)result, kCFStringNormalizationFormD); CFStringFold((CFMutableStringRef)result, kCFCompareCaseInsensitive | kCFCompareDiacriticInsensitive | kCFCompareWidthInsensitive, NULL); self.canonicalizedDesc = [NSString stringWithString:result];}

Page 55: High Performance Core Data

- (void)setDesc:(NSString *)desc { if (_desc != desc) { _desc = desc; [self updateCanonicalizedDesc:desc]; }}

- (void)updateCanonicalizedDesc:(NSString *)desc { NSMutableString *result = [NSMutableString stringWithString:desc]; CFStringNormalize((CFMutableStringRef)result, kCFStringNormalizationFormD); CFStringFold((CFMutableStringRef)result, kCFCompareCaseInsensitive | kCFCompareDiacriticInsensitive | kCFCompareWidthInsensitive, NULL); self.canonicalizedDesc = [NSString stringWithString:result];}

Page 56: High Performance Core Data

Canonicalized Tokens

Page 57: High Performance Core Data
Page 58: High Performance Core Data
Page 59: High Performance Core Data

componentsSeperatedByCharactersInSet

Page 60: High Performance Core Data

Separate Stack

Page 61: High Performance Core Data

Managed ObjectContext

Persistent StoreCoordinator

Persistent Store(SQLite, XML, ...)

Model

Primary

Managed ObjectContext

Persistent StoreCoordinator

Persistent Store(SQLite, XML, ...)

Model

Search Tokens

Page 62: High Performance Core Data

Managed ObjectContext

Persistent StoreCoordinator

Persistent Store(SQLite, XML, ...)

Model

Primary

Managed ObjectContext

Persistent StoreCoordinator

Persistent Store(SQLite, XML, ...)

Model

Search Tokens

URIRepresentation

Page 63: High Performance Core Data

Hash of Tokens

Page 64: High Performance Core Data

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

Page 65: High Performance Core Data

Data Model

Page 66: High Performance Core Data

Don’t Overnormalize•Duplication isn’t always bad•Let UI drive data model

Page 67: High Performance Core Data

Use External Storage

Page 68: High Performance Core Data
Page 69: High Performance Core Data
Page 70: High Performance Core Data
Page 71: High Performance Core Data
Page 72: High Performance Core Data

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

Page 73: High Performance Core Data

App Launch

Page 74: High Performance Core Data

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ // Create persistent store coordinator with model // Add persistent store to store coordinator // Create managed object context // Context is fully initialized, notify view controllers dispatch_sync(dispatch_get_main_queue(), ^{ [self persistentStackInitialized]; }); });

Page 75: High Performance Core Data

“Lots of Things” Problem

Page 76: High Performance Core Data

- (void)applicationDidEnterBackground:(UIApplication *)application {

UIApplication *app = [UIApplication sharedApplication]; __block UIBackgroundTaskIdentifier backgroundTask = 0; backgroundTask = [app beginBackgroundTaskWithExpirationHandler:^{ [app endBackgroundTask:backgroundTask]; backgroundTask = UIBackgroundTaskInvalid; }]; dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // Delete or update a bunch of NSManagedObjects

// If success [app endBackgroundTask:backgroundTask]; backgroundTask = UIBackgroundTaskInvalid;

// If failure [app endBackgroundTask:backgroundTask]; backgroundTask = UIBackgroundTaskInvalid; }); }

Page 77: High Performance Core Data

Importing Data

Page 78: High Performance Core Data
Page 79: High Performance Core Data

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

Page 80: High Performance Core Data

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

NSManagedObjectContext *privateManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];

[privateManagedObjectContext setPersistentStoreCoordinator: self.managedObjectContext.persistentStoreCoordinator];privateManagedObjectContext.undoManager = nil;

[privateManagedObjectContext performBlockAndWait:^{ [self import];}];

Page 81: High Performance Core Data
Page 82: High Performance Core Data

Typical Import Algorithm

1) JSON to NSDictionary

2) Find existing NSManagedObject

3) Optionally, create new NSManagedObject

4) Set attributes of new/updated NSManagedObject

Page 83: High Performance Core Data

Typical Import Algorithm

1) JSON to NSDictionary

2) Find existing NSManagedObject

3) Optionally, create new NSManagedObject

4) Set attributes of new/updated NSManagedObject

Page 84: High Performance Core Data

Inefficient Find-Or-Create Algorithm+ (instancetype)findOrCreateWithIdentifier:(id)identifier inContext:(NSManagedObjectContext *)context { NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"UFOSighting”]; fetchRequest.predicate = [NSPredicate predicateWithFormat:@"%K = %@", @"GUID”, identifier]; fetchRequest.fetchLimit = 1; id object = [[context executeFetchRequest:fetchRequest error:NULL] lastObject]; if (object == nil) { object = [UFOSighting insertNewObjectIntoContext:context]; } return object;}

Page 85: High Performance Core Data

Inefficient Find-Or-Create Algorithm+ (instancetype)findOrCreateWithIdentifier:(id)identifier inContext:(NSManagedObjectContext *)context { NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"UFOSighting”]; fetchRequest.predicate = [NSPredicate predicateWithFormat:@"%K = %@", @"GUID”, identifier]; fetchRequest.fetchLimit = 1; id object = [[context executeFetchRequest:fetchRequest error:NULL] lastObject]; if (object == nil) { object = [UFOSighting insertNewObjectIntoContext:context]; } return object;}

Page 86: High Performance Core Data

1

2

3

4

...

New Data

1

4

...

Old Data

Page 87: High Performance Core Data

1

2

3

4

...

New Data

1

4

...

Old DataUpdate

Page 88: High Performance Core Data

1

2

3

4

...

New Data

1

4

...

Old Data

Insert

Page 89: High Performance Core Data

1

2

3

4

...

New Data

1

4

...

Old Data

2

Page 90: High Performance Core Data

1

2

3

4

...

New Data

1

4

...

Old Data

2

Page 91: High Performance Core Data

1

2

3

4

...

New Data

1

4

...

Old Data

2Insert

Page 92: High Performance Core Data

1

2

3

4

...

New Data

1

4

...

Old Data

2

3

Page 93: High Performance Core Data

1

2

3

4

...

New Data

1

4

...

Old Data

2

3Update

Page 94: High Performance Core Data

Inefficient Find-Or-Create Algorithm

NSEnumerator *jsonEnumerator = [sortedArray objectEnumerator];NSEnumerator *fetchResultsEnumerator = [fetchResults objectEnumerator];NSDictionary *UFOSightingDictionary = [jsonEnumerator nextObject];UFOSighting *UFOSightingManagedObject = [fetchResultsEnumerator nextObject];

while (UFOSightingDictionary) { // Check if managed object already exist // Not an update, create new managed object // Set new attributes if (isUpdate) { UFOSightingDictionary = [jsonEnumerator nextObject]; UFOSightingManagedObject = [fetchResultsEnumerator nextObject]; } else { UFOSightingDictionary = [jsonEnumerator nextObject]; }}

Page 95: High Performance Core Data

Inefficient Find-Or-Create Algorithm

NSEnumerator *jsonEnumerator = [sortedArray objectEnumerator];NSEnumerator *fetchResultsEnumerator = [fetchResults objectEnumerator];NSDictionary *UFOSightingDictionary = [jsonEnumerator nextObject];UFOSighting *UFOSightingManagedObject = [fetchResultsEnumerator nextObject];

while (UFOSightingDictionary) { // Check if managed object already exist // Not an update, create new managed object // Set new attributes if (isUpdate) { UFOSightingDictionary = [jsonEnumerator nextObject]; UFOSightingManagedObject = [fetchResultsEnumerator nextObject]; } else { UFOSightingDictionary = [jsonEnumerator nextObject]; }}

Page 96: High Performance Core Data

Inefficient Find-Or-Create Algorithm

NSEnumerator *jsonEnumerator = [sortedArray objectEnumerator];NSEnumerator *fetchResultsEnumerator = [fetchResults objectEnumerator];NSDictionary *UFOSightingDictionary = [jsonEnumerator nextObject];UFOSighting *UFOSightingManagedObject = [fetchResultsEnumerator nextObject];

while (UFOSightingDictionary) { // Check if managed object already exist // Not an update, create new managed object // Set new attributes if (isUpdate) { UFOSightingDictionary = [jsonEnumerator nextObject]; UFOSightingManagedObject = [fetchResultsEnumerator nextObject]; } else { UFOSightingDictionary = [jsonEnumerator nextObject]; }}

Page 97: High Performance Core Data

Inefficient Find-Or-Create Algorithm

NSEnumerator *jsonEnumerator = [sortedArray objectEnumerator];NSEnumerator *fetchResultsEnumerator = [fetchResults objectEnumerator];NSDictionary *UFOSightingDictionary = [jsonEnumerator nextObject];UFOSighting *UFOSightingManagedObject = [fetchResultsEnumerator nextObject];

while (UFOSightingDictionary) { // Check if managed object already exist // Not an update, create new managed object // Set new attributes if (isUpdate) { UFOSightingDictionary = [jsonEnumerator nextObject]; UFOSightingManagedObject = [fetchResultsEnumerator nextObject]; } else { UFOSightingDictionary = [jsonEnumerator nextObject]; }}

Page 98: High Performance Core Data
Page 99: High Performance Core Data

NSUInteger totalUFOSightings = [UFOSightingsArray count];NSInteger totalBatches = totalUFOSightings / MDM_BATCH_SIZE_IMPORT; // Create array with just the unique keysNSArray *jsonGUIDArray = [sortedArray valueForKey:UFO_KEY_JSON_GUID]; for (NSInteger batchCounter = 0; batchCounter <= totalBatches; batchCounter++) {

// Create batch range based on batch size NSRange range = NSMakeRange(batchCounter*MDM_BATCH_SIZE_IMPORT,MDM_BATCH_SIZE_IMPORT); NSArray *jsonBatchGUIDArray = [jsonGUIDArray subarrayWithRange:range]; // Grab sorted persisted managed objects, based on the batch NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]initWithEntityName:@"UFOSighting"]; NSPredicate *fetchPredicate = [NSPredicate predicateWithFormat:@"%K IN %@", @"GUID", jsonBatchGUIDArray]; // ...

while (UFOSightingDictionary) { // ... // Efficient find-or-create algorithm // ... }}

Page 100: High Performance Core Data

NSUInteger totalUFOSightings = [UFOSightingsArray count];NSInteger totalBatches = totalUFOSightings / MDM_BATCH_SIZE_IMPORT; // Create array with just the unique keysNSArray *jsonGUIDArray = [sortedArray valueForKey:UFO_KEY_JSON_GUID]; for (NSInteger batchCounter = 0; batchCounter <= totalBatches; batchCounter++) {

// Create batch range based on batch size NSRange range = NSMakeRange(batchCounter*MDM_BATCH_SIZE_IMPORT,MDM_BATCH_SIZE_IMPORT); NSArray *jsonBatchGUIDArray = [jsonGUIDArray subarrayWithRange:range]; // Grab sorted persisted managed objects, based on the batch NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]initWithEntityName:@"UFOSighting"]; NSPredicate *fetchPredicate = [NSPredicate predicateWithFormat:@"%K IN %@", @"GUID", jsonBatchGUIDArray]; // ...

while (UFOSightingDictionary) { // ... // Efficient find-or-create algorithm // ... }}

Page 101: High Performance Core Data

NSUInteger totalUFOSightings = [UFOSightingsArray count];NSInteger totalBatches = totalUFOSightings / MDM_BATCH_SIZE_IMPORT; // Create array with just the unique keysNSArray *jsonGUIDArray = [sortedArray valueForKey:UFO_KEY_JSON_GUID]; for (NSInteger batchCounter = 0; batchCounter <= totalBatches; batchCounter++) {

// Create batch range based on batch size NSRange range = NSMakeRange(batchCounter*MDM_BATCH_SIZE_IMPORT,MDM_BATCH_SIZE_IMPORT); NSArray *jsonBatchGUIDArray = [jsonGUIDArray subarrayWithRange:range]; // Grab sorted persisted managed objects, based on the batch NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]initWithEntityName:@"UFOSighting"]; NSPredicate *fetchPredicate = [NSPredicate predicateWithFormat:@"%K IN %@", @"GUID", jsonBatchGUIDArray]; // ...

while (UFOSightingDictionary) { // ... // Efficient find-or-create algorithm // ... }}

Page 102: High Performance Core Data

Pre-Populated SQLiteFile in App Bundle

Page 103: High Performance Core Data

Download Pre-PopulatedSQLite File

Page 104: High Performance Core Data

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

Page 105: High Performance Core Data

Memory

Page 106: High Performance Core Data

[context refreshObject:UFOSightingManagedObject mergeChanges:NO];

[context reset];

Page 107: High Performance Core Data

ConcurrencyModels

Page 108: High Performance Core Data

Managed ObjectContext

ManagedObject

ManagedObject

Persistent StoreCoordinator

Persistent Store(SQLite, XML, ...)

Model

Main Queue

Page 109: High Performance Core Data

Managed ObjectContext

ManagedObject

ManagedObject

Persistent StoreCoordinator

Persistent Store(SQLite, XML, ...)

Model

Main Queue

Page 110: High Performance Core Data

Managed ObjectContext

Persistent StoreCoordinator

Persistent Store(SQLite, XML, ...)

Model

Managed ObjectContext

Main Queue Private Queue

Page 111: High Performance Core Data

Managed ObjectContext

Persistent StoreCoordinator

Persistent Store(SQLite, XML, ...)

Model

Managed ObjectContext

Main Queue Private Queue

Page 112: High Performance Core Data

Managed ObjectContext

Persistent StoreCoordinator

Persistent Store(SQLite, XML, ...)

Model

Managed ObjectContext

Main Queue Private Queue

Context Did SaveNotification

Merge Changes From Notification

Page 113: High Performance Core Data

Managed ObjectContext

Persistent StoreCoordinator

Persistent Store(SQLite, XML, ...)

Model

Managed ObjectContext

Main Queue Private Queue

Context Did SaveNotification

Refetch andReload

Page 114: High Performance Core Data

Persistent StoreCoordinator

Persistent Store

Model

Main Queue

Managed ObjectContext

Managed ObjectContext

Private Queue

Page 115: High Performance Core Data

Persistent StoreCoordinator

Persistent Store

Model

Main Queue

Managed ObjectContext

Managed ObjectContext

Private Queue

UI Work

Page 116: High Performance Core Data

Persistent StoreCoordinator

Persistent Store

Model

Main Queue

Managed ObjectContext

Managed ObjectContext

Private Queue

UI Work

Persisting toDisk

Page 117: High Performance Core Data

Persistent StoreCoordinator

Persistent Store

Model

Main Queue

Managed ObjectContext

Managed ObjectContext

Private Queue

UI Work

Persisting toDisk

Page 118: High Performance Core Data

Persistent StoreCoordinator

Persistent Store

Model

Main Queue

Managed ObjectContext

Managed ObjectContext

Private Queue

UI Work

Persisting toDisk

Page 119: High Performance Core Data

Persistent StoreCoordinator

Persistent Store

Model

Main Queue

Managed ObjectContext

Private Queue

Managed ObjectContext

Managed ObjectContext

Private Queue

Page 120: High Performance Core Data

Persistent StoreCoordinator

Persistent Store

Model

Main Queue

Managed ObjectContext

Private Queue

Managed ObjectContext

Managed ObjectContext

Private Queue

Background Updates

Page 121: High Performance Core Data

Persistent StoreCoordinator

Persistent Store

Model

Main Queue

Managed ObjectContext

Private Queue

Managed ObjectContext

Managed ObjectContext

Private Queue

Background Updates

UI Work

Page 122: High Performance Core Data

Persistent StoreCoordinator

Persistent Store

Model

Main Queue

Managed ObjectContext

Private Queue

Managed ObjectContext

Managed ObjectContext

Private Queue

Background Updates

UI Work

Persisting toDisk

Page 123: High Performance Core Data

Persistent StoreCoordinator

Persistent Store

Model

Main Queue

Managed ObjectContext

Private Queue

Managed ObjectContext

Managed ObjectContext

Private Queue

Background Updates

UI Work

Persisting toDisk

Page 124: High Performance Core Data

Persistent StoreCoordinator

Persistent Store

Model

Main Queue

Managed ObjectContext

Private Queue

Managed ObjectContext

Managed ObjectContext

Private Queue

Background Updates

UI Work

Persisting toDisk

__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

Page 125: High Performance Core Data
Page 126: High Performance Core Data

Managed ObjectContext

Persistent StoreCoordinator

Persistent Store(SQLite, XML, ...)

Model

Managed ObjectContext

Main Queue Private Queue

Persistent StoreCoordinator

Model

Page 127: High Performance Core Data

Managed ObjectContext

Persistent StoreCoordinator

Persistent Store(SQLite, XML, ...)

Model

Managed ObjectContext

Main Queue Private Queue

Persistent StoreCoordinator

Model

Page 128: High Performance Core Data

Managed ObjectContext

Persistent StoreCoordinator

Persistent Store(SQLite, XML, ...)

Model

Managed ObjectContext

Main Queue Private Queue

Persistent StoreCoordinator

Model

Page 129: High Performance Core Data

Managed ObjectContext

Persistent StoreCoordinator

Persistent Store(SQLite, XML, ...)

Model

Managed ObjectContext

Main Queue Private Queue

Persistent StoreCoordinator

Model

Context Did SaveNotification

Page 130: High Performance Core Data

Managed ObjectContext

Persistent StoreCoordinator

Persistent Store(SQLite, XML, ...)

Model

Managed ObjectContext

Main Queue Private Queue

Persistent StoreCoordinator

Model

Context Did SaveNotification

Merge Changes From Notification

Page 131: High Performance Core Data

Managed ObjectContext

Persistent StoreCoordinator

Persistent Store(SQLite, XML, ...)

Model

Managed ObjectContext

Main Queue Private Queue

Persistent StoreCoordinator

Model

Context Did SaveNotification

Refetch andReload

Page 132: High Performance Core Data
Page 133: High Performance Core Data

Managed ObjectContext

Persistent StoreCoordinator

Persistent Store(SQLite, XML, ...)

Model

Managed ObjectContext

Main Queue Private Queue

Persistent StoreCoordinator

Model

Context Did SaveNotification

Refetch andReload

•Cannot pass objects between persistent store coordinators

•Cannot pass objectIDs between persistent store coordinators

•You can use URIRepresentation

•You can use mergeChangesFromContextDidSaveNotification

Page 134: High Performance Core Data

TLDR

Page 135: High Performance Core Data

Managed ObjectContext

Persistent StoreCoordinator

Persistent Store(SQLite, XML, ...)

Model

Managed ObjectContext

Main Queue Private Queue

Context Did SaveNotification

Refetch andReload

Page 136: High Performance Core Data

Concurrency Models

•Use the simplest model that meets your needs

•Update main context after large imports have completed

Page 137: High Performance Core Data

BangHeadHere

Page 138: High Performance Core Data

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

Page 139: High Performance Core Data

Questions?

HighPerformanceCoreData.com

MatthewMorey.com | @xzolian