Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change default NSManagedObjectContext of NSPersistentDocument

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.

like image 726
insys Avatar asked Jun 13 '26 16:06

insys


1 Answers

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.

like image 100
Aaron Burghardt Avatar answered Jun 15 '26 12:06

Aaron Burghardt