Question

Core data newbie here. I'm trying to change the default NSManagedObjectContext of an NSPersistentDocument, in order to initialise and use it with NSMainQueueConcurrencyType.

Currently I'm doing it in -windowControllerDidLoadNib: like this:

- (void)windowControllerDidLoadNib:(NSWindowController *)aController
{
    [super windowControllerDidLoadNib:aController];
    NSManagedObjectContext *newMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    [newMOC setPersistentStoreCoordinator:[self.managedObjectContext persistentStoreCoordinator]];
    [self setManagedObjectContext:newMOC];
}

This seemingly works fine. But I'm wondering if initialisation of the MOC in -windowControllerDidLoadNib: is the best thing to do, or whether it should be placed somewhere else and/or initialised in a different way.

Thanks for any help.

Was it helpful?

Solution 2

The preferred pattern is the "pass-the-baton" approach where you pass the managed object context down to the child view controllers. Give your controllers a managed object context attribute and simply pass it on when you present them.

OTHER TIPS

I'm experimenting with the Xcode template for a document-based CoreData app. The template creates an init() override which just calls super.init(). I want to run a large import in the background, so I added this to the document class:

class Document: NSPersistentDocument {

    private var importQueue = DispatchQueue(label: "Importer")

    override init() {
        super.init()

        let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
        moc.mergePolicy = self.managedObjectContext!.mergePolicy
        moc.persistentStoreCoordinator = self.managedObjectContext!.persistentStoreCoordinator
        self.managedObjectContext = moc
    }

    func importStuff(url: URL) {

        let moc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
        moc.parent = self.managedObjectContext

        var count = 0

        moc.performAndWait {
            ...

            count += 1
            if count % 10000 == 0 {
                do {
                    try moc.save()
                    moc.reset()
                }
                catch {
                    Swift.print("save failed at record #\(count): \(error.localizedDescription)")
                }
            }
            return true
        }

        do {
            try moc.save()
        }
        catch {
            Swift.print("save failed at records #\(count): \(error.localizedDescription)")
        }

    }

    Swift.print("imported \(count) records.")
}

@IBAction func import(_ sender: Any) {

        ...

        importQueue.async {
            self.importStuff(url: url)
        }
    }
}

This seems to work OK in my initial tests. I think initializing a new MOC in -windowControllerDidLoadNib: is OK, but if you have object controllers bound to the document MOC, they might perform a second fetch when the MOC is changed. Initializing it in the init will initialize it sooner, before the UI is loaded.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top