1

My macOS app needs to periodically download user read-only data (like stock prices). To do this I have built a dual-context system:

@interface MyCoreDataStackManager : NSObject

@property (nonatomic, readonly) NSManagedObjectModel* managedObjectModel;
@property (nonatomic, readonly) NSPersistentStoreCoordinator* persistentStoreCoordinator;
@property (nonatomic, readonly) NSManagedObjectContext* managedObjectContext;
@property (nonatomic, readonly) NSURL* applicationSupportDirectory;
@property (nonatomic, readonly) NSURL* storeURL;

During init, the stack is constructed with an NSSQLiteStoreType and NSMainQueueConcurrencyType.

To be able to do background downloading and processing, I also have a method to create a separate context using the same model and store but with it's own NSPersistentStoreCoordinator. The private context uses NSPrivateQueueConcurrencyType.

-(NSManagedObjectContext *)privateContext
{
    NSManagedObjectContext* privateContext = nil;
    NSError* error = nil;

    //  Use the same store and model, but a new persistent store coordinator unique to this context.
    NSPersistentStoreCoordinator* privateCoordinator = [[[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]] autorelease];
    if (privateCoordinator)
    {
        NSPersistentStore* privateStore = [privateCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[self storeURL] options:nil error:&error];
        if (privateStore)
        {
            privateContext = [[[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType] autorelease];
            if (privateContext)
            {
                [privateContext setPersistentStoreCoordinator:privateCoordinator];
                [privateContext setUndoManager:nil];
            }
        }
    }

    return (privateContext);
}

This blog post does it a similar way but makes the private context be the parent of the main-thread managedObjectContext:

http://martiancraft.com/blog/2015/03/core-data-stack/

[[self managedObjectContext] setParentContext:[self privateContext]];

This blog post also does it in a similar way but makes the main-thread context be the parent of the private context (under "Strategy 2"):

https://code.tutsplus.com/tutorials/core-data-from-scratch-concurrency--cms-22131

[self.privateManagedObjectContext setParentContext:self.mainManagedObjectContext];

The way mine works right now is that neither context is the parent of the other, they just use the same store and it seems to work fine. This methodology is based on an Apple example for downloading earthquake data which used to be in Obj-C but is now only available in Swift.

https://developer.apple.com/library/archive/samplecode/Earthquakes/Introduction/Intro.html

Why are the first two opposite and what are the pros/cons/differences of doing it each way? Why does the Apple example not use a parent at all?

Furthermore, some examples (in similar cases) show both contexts sharing a single NSPersistentStoreCoordinator but mine (as the examples above) have each context owning its own PSC, even though they each point to the same store file. What is the better way?

I have one case where the user can edit the downloaded data. Would it make a difference there as to who (if any) is the parent context?

Trygve
  • 1,317
  • 10
  • 27

0 Answers0