Hello everyone,
I'm building a SwiftUI app (iOS 15+) using Core Data. My post is simply out of interest, as I already found a workaround for the issue I had, but if someone could explain me why I had to do it this way, I'd be more than happy to learn why!
(For the sake of simplicity I show you a simplistict version of my code with only the interesting parts.)
After being able to add and list items (using Paul's awesome articles), I of course wanted to edit items! This is where I ended up watching Donny Wals' talk about this and followed his approach (https://youtu.be/P8rqjs_CNsk?t=1700) of using a viewModel which stores a temporary NSManagedObject in a child context, before persisting it to the main context when we are done. Clever.
In his video the viewModel is a struct, which is stored as a @State variable in the editing View. In my case I have some controls in this editing View which appear/disappear/change depending of other values the user changes (switchs, fields, whatever…).
My initial viewModel based on Donny Wals (persistenceController functions can be found in his talk, but I don't belive it really matters for my problem):
struct EditViewModel {
var item: Item // This is a NSManagedObject
private let childContext: NSManagedObjectContext
private let persistenceController = PersistenceController.shared
init(item: Item? = nil) {
self.childContext = persistenceController.childViewContext()
if let item = item {
self.item = persistenceController.copyForEditing(of: item, in: childContext)
} else {
self.item = persistenceController.newTemporaryInstance(in: childContext)
}
}
// More functions below to persist changes, etc.
}
And my EditView:
struct EditView: View {
@State private var vm: EditViewModel
init(item: Item? = nil) {
_vm = State(initialValue: EditViewModel(item: item))
}
var body: some View {
Form {
Text(vm.item.text) // Should update when we change text in the TextField below.
TextField("", text: $vm.item.text)
}
}
}
With this code, the issue I've faced is the Text view doesn't seem to reflect changes when we edit the TextField.
Changing my viewModel for a class does the trick, and it works fine:
class EditViewModel: ObservableObject {
@Published var item: Item // This is a NSManagedObject
// ...
}
The big question is why! Why do I have to use an ObservableObject. From what I understood, a struct as a @State should behaves the same, no? Is this related to the NSManagedObject under-the-hood architecture?
Thanks for enlightening me on this weird thing!