6

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().

1

3 Answers 3

3

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.

Sign up to request clarification or add additional context in comments.

1 Comment

David - Can you say anything more about passing in a child context in SwiftUI?
1

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.

Comments

0

My problem was that I had @Environment(\.managedObjectContext) static var context and then @ObservedObject var myModel: MyManagedObjectClass = MyManagedObjectClass(context: context) ... evidently it does not like the context being static.

In order to have an actual NSManagedObject subclass as a property of the view to use bindings to its properties, unless that object is on a parent view then it should be an @State variable and get populated as part of the init method of the view. (The source of truth is that property on the view.)

The other approach is to only create and set the properties of the managed object in the actual save method on the view.

But if you try to have an @ObservedObject that gets initted when the view is created like @ObservedObject var myModel: MyManagedObjectClass = MyManagedObjectClass(context: context) with context as a static property then this simply won't work because context will be nil when the object gets created.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.