Search code examples
core-dataswiftuiswift-concurrency

SwifttUI with Core Data: load from private context


I am trying to display some objects in SwiftUI that I created using an NSManagedObjectContext set to a private queue (so that in case the user presses cancel, the objects aren't committed anywhere, basically the 'scratchpad' MOC). I initially create new a background context:

let privateMOC = appDelegate.persistentContainer.newBackgroundContext()

Then I create new objects using this background context, and set the environment variable for managedObjectContext to this MOC:

let rootView = ImportCSVMappingFieldsPage().environment(\.managedObjectContext, privateMOC)

I then want to display the created objects in the SwiftUI view. However, when I do this, the app crashes and I get this error:

SwiftUI/FetchCommon.swift:47: Fatal error: Can only use main queue contexts to drive SwiftUI

Is there something I'm missing here? I should be able to display objects created with a background managedObjectContext inside a SwiftUI view, right?


Solution

  • A background context is for performing work in the background. If you want a scratchpad context for managing user edits, you need to make a main queue context:

    let editingContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
    editingContext.parent = appDelegate.persistentContainer.viewContext
    
    let rootView = ImportCSVMappingFieldsPage().environment(\.managedObjectContext, editingContext)
    

    When you save this context, the changes will be merged back to the view context. If you cancel and the context is destroyed, the changes are discarded.

    If you want to do work on a background queue, then make user edits, and have the entirety of that work be disposable, then create a background queue context with the parent of the editing context above. When the background work is finished, save the background context. The editing context will now have that data available to work with or discard as you please.