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.
Change default NSManagedObjectContext of NSPersistentDocument
-
19-06-2023 - |
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.
Solution 2
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.