For now, ignore MagicalRecord. To work with master data across multiple threads, you need to know a few things.
- Do not skip
NSManagedObject between threads. Instead, go to the NSManagedObjectID for the object you want and retrieve it in the background thread. - Responsibly create an
NSManagedObjectContext . That means you should know what initWithConcurrencyType: means. We will consider this.
Main theme
Your main NSManagedObjectContext should be built with the concurrency type NSMainQueueConcurrencyType . This will allow you to use the queued contexts for sequential operations. Each time a background thread interacts with the main context, you must do the work using performBlock or performBlockAndWait .
- (NSManagedObjectContext *)managedObjectContext { if (_managedObjectContext != nil) { return _managedObjectContext; } NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; if (coordinator != nil) { _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; [_managedObjectContext setPersistentStoreCoordinator:coordinator]; } return _managedObjectContext; }
Background theme
Whenever you do work in the background thread, you need to expand a new context. You should not share contexts between threads. Pass the link to your main thread context into your operation and create a background context after your operation starts. This will ensure that it builds on the thread where you will do the work.
- (NSManagedObjectContext *)newBackgroundManagedObjectContext { // Create new context with private concurrency type NSManagedObjectContext *newContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; [newContext setParentContext:self.mainContext]; // Optimization [newContext setUndoManager:nil]; return newContext; }
Think of this background context as scratching. Whatever you do, they will remain there until you save. As you set parentContext, saving in the background context will merge the changes into your main context. This will update the NSFetchedResultsController , but the data has not yet been saved since you did not invoke the save. In your KVO queue, you can invoke a save in the main context by queuing a save block.
[self performBlock:^{ NSError *error; [self save:&error]; if (error) {
source share