Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Core Data save from within a SwiftUI fails

I am working on an app that combines Core Data with SwiftUI. Everything went well until I put my update code into a sheet, after that I got a "Foundation._GenericObjCError" error of 0 which I believe means no error but my persistent container still didn't get updated.

Is this combination a known problem?

The code I am using to add entries to my Store entry:

struct StoreAdd: View {
    @Environment(\.managedObjectContext)
    var managedObjectContext

    @State
    var name = ""
    @State
    var branch = ""

    var body: some View {
        VStack {
            TextField("Store name", text: $name)
            TextField("Store branch", text: $branch)
            Button(
                action: {
                    let store = Store(context: self.managedObjectContext)
                    store.id = UUID()
                    store.name = self.name
                    store.branch = self.branch.isEmpty ? nil : self.branch
                    self.managedObjectContext.persist()
                },
                label: { Text("Add")}
            )
            .disabled(name.isEmpty)
        }
        .padding(.horizontal, 20)
    }
}

persist() is a wrapper around save().

like image 810
Michael Salmon Avatar asked Oct 01 '19 14:10

Michael Salmon


2 Answers

I also ran into this problem. I was under the misconception that the @Environment vars were in some sort of global store, or at least a store that was unique to each SceneDelegate.

However it seems that Environment is hierarchical, automatically passed down to its descendants and is not passed onto modals. I'm guessing that in your case you have used something like .sheet to open your StoreAdd view. This actually causes StoreAdd to get a completely empty environment. I found that I could solve this error by doing something like this:

.sheet(isPresented: $showAddSheet, content: { StoreAdd().environment(\.managedObjectContext, self.managedObjectContext) } )

I don't know if this is a bug or by design. It does allow for some interesting ideas like passing in a temporary child context for edits.

like image 71
David Monagle Avatar answered Jan 02 '23 21:01

David Monagle


I found that the problem was in the declaration of managedObjectContext. Fetching it from the environment didn't work but passing it as a parameter does even though it is fetched in the parent View from the environment.

like image 41
Michael Salmon Avatar answered Jan 02 '23 20:01

Michael Salmon