I have an app that generates top level CoreData Entities that have multiple levels of child entities that take some time to generate. I'm trying to avoid locking up the main thread so that the app doesn't become unresponsive.
I've attempted to create a second background ManagedObjectContext to run on a different thread, first by creating a new EnvironmentKey:
private struct BackgroundMOCEnvironmentKey: EnvironmentKey {
static let defaultValue: NSManagedObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
}
extension EnvironmentValues {
var backgroundManagedObjectContext: NSManagedObjectContext {
get { self[BackgroundMOCEnvironmentKey.self] }
set { self[BackgroundMOCEnvironmentKey.self] = newValue }
}
}
I've then passed this to the ContentView() in the App swift file containing a new background Managed Object Context:
var body: some Scene {
WindowGroup {
ContentView()
.environment(\.managedObjectContext, persistenceController.container.viewContext)
.environment(\.backgroundManagedObjectContext, persistenceController.container.newBackgroundContext())
}
.onChange(of: scenePhase) { _ in
persistenceController.save()
}
}
In the struct I've written to perform the background tasks, I reference the new background Managed Object Context
struct GameDataGenerator {
@Environment(\.backgroundManagedObjectContext) var moc
func generateData(forObjectID objectID: NSManagedObjectID, gridSize: Int, gameDepth: Int) {
let managedObject = moc.object(with: objectID) // The parent Entity
In the ContentView onAppear modifier, I run a process that genererates, and saves, the top level Entity on the main thread using environment(.managedObjectContext) so that it appears in the UI.
I then call generateData() asyncronously, passing it the objectID so that it can carry on generating the rest of the data:
let generator = GameDataGenerator()
DispatchQueue.main.async {
generator.generateData(forObjectID: gameTile.objectID, gridSize: gridSize, gameDepth: gameDepth)
}
I'm getting an error saying that the "persistent store is not reachable from this NSManagedObjectContext's coordinator".
Please could anyone advise if there is a better/simpler way to run background tasks against CoreData Entities, or see if they can spot a problem with my approach above?
Thanks!