I have an issue exposing my NSManagedObjectContext to SwiftUI's Environment. Here's my code:
extension SceneDelegate: UIWindowSceneDelegate {
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = scene as? UIWindowScene else { return }
let window = UIWindow(windowScene: windowScene)
let context = PersistentContainer.shared.viewContext
let rootView = TabBarView().environment(\.managedObjectContext, context)
window.rootViewController = UIHostingController(rootView: rootView)
self.window = window
window.makeKeyAndVisible()
}
}
class PersistentContainer: NSPersistentContainer {
static let shared = PersistentContainer()
private convenience init() {
self.init(name: "App")
viewContext.mergePolicy = NSMergePolicy(merge: .mergeByPropertyStoreTrumpMergePolicyType)
viewContext.automaticallyMergesChangesFromParent = true
loadPersistentStores { description, error in
if let error = error {
fatalError("Unable to load persistent stores: \(error)")
}
}
}
}
struct CategoriesView: View {
@Environment(\.managedObjectContext) var context
@FetchRequest(entity: CoreCategory.entity(),
sortDescriptors: [
NSSortDescriptor(keyPath: \CoreCategory.createdAt, ascending: true)
]
) var categories: FetchedResults<CoreCategory>
}
My CategoriesView
is my root view, so the context is accessed on app launch. I get the following error when my app launches ...
[error] warning: View context accessed for persistent container App with no stores loaded
... yet the view is able to display results fine. Furthermore, if I present a modal view that contains a SwiftUI @FetchRequest
in the same format as my CategoriesView, the app crashes with the following error:
[SwiftUI] Context in environment is not connected to a persistent store coordinator: <NSManagedObjectContext: 0x600002348b60>
From all the tutorials I found online I'm exposing my NSManagedObjectContext
the recommended way. I have a feeling it's related to loadPersistentStores
being asynchronous, but the context being set in the Environment synchronously. Anyone else able to get CoreData to work in SwiftUI?
Core Data is designed to work in a multithreaded environment. However, not every object under the Core Data framework is thread safe. To use Core Data in a multithreaded environment, ensure that: Managed object contexts are bound to the thread (queue) that they are associated with upon initialization.
An object space to manipulate and track changes to managed objects.
Use Core Data to save your application's permanent data for offline use, to cache temporary data, and to add undo functionality to your app on a single device. To sync data across multiple devices in a single iCloud account, Core Data automatically mirrors your schema to a CloudKit container.
Figured out what's causing both error messages here. The first error is coming from my PersistentContainer
singleton. I moved the two lines configuring the viewContext
into the loadPersistentStores
completion block, and those warnings went away:
private convenience init() {
self.init(name: "App")
loadPersistentStores { description, error in
viewContext.mergePolicy = NSMergePolicy(merge: .mergeByPropertyStoreTrumpMergePolicyType)
viewContext.automaticallyMergesChangesFromParent = true
if let error = error {
fatalError("Unable to load persistent stores: \(error)")
}
}
}
The second issue is apparently an issue with SwiftUI since the betas. There's a thread about it on the Apple Dev Forums here. You can do this as a workaround:
.sheet(isPresented: $isPresentingCategoryPicker) {
CategoriesView()
.environment(\.managedObjectContext, self.context)
}
It seems the environment gets cleared for modally presented view controllers.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With