英文:
Why does Binding of CoreData NSManagedObject not update onChange in Swift?
问题
问题的原因是在DetailView中,本地的Toggle状态改变时,未能正确地触发entity.enabled的绑定。解决方法是确保在localEnabled改变时,手动更新绑定的entity.enabled。可以尝试在DetailView的onChange闭包中,显式地将entity.enabled的值设置为localEnabled:
.onChange(of: localEnabled) { newValue in
    entity.enabled = newValue
}
英文:
Context
I have a pretty simple Form using the MVVM architecture. However, I encountered a problem with this implementation. My DetailView has a DummyState that changes the corresponding attribute of Entity onChange.
> Problem: Once the DetailView appears, both Toggles are on which is as expected. However, when turning the local Toggle off, the other Toggle remains on, which is unexpected. However, as soon as I interact with another element (not in MRE), the second Toggle seems to refresh and turns off.
Code
@objc(Entity) public class Entity: NSManagedObject {
    @NSManaged public var enabled: Bool
}
class FormViewModel: ObservableObject, CustomFormObservable {
    @Published var entity = Entity(context: ...)
    init() { self.entity.enabled = true }
    var isValid: Bool { self.entity.enabled }
}
struct FormView: View {
    @StateObject private var formVM = FormViewModel()
    var body: some View {
        CustomForm(formVM: formVM) {
            DetailView(entity: $formVM.entity)
        }
    }
}
struct DetailView: View {
    @Binding var entity: Entity
    @State private var localEnabled: Bool = true
    var body: some View {
        Toggle("Local Toggle", isOn: $localEnabled)
            .onChange(of: localEnabled) { entity.enabled = $0 }
        Toggle("Toggle", isOn: $entity.enabled)
    }
}
Question
- What causes this behaviour and how can I solve it?
 
答案1
得分: 1
因为 NSManagedObject 是引用类型。
有一个简单的规则:
@State和@Binding用于值类型,如结构体。@StateObject和@ObservedObject用于引用类型,如类。
而且 美元符号引用 也仅用于值类型。
幸运的是,NSManagedObject 默认符合 ObservableObject。
struct MainView: View {
    @StateObject private var formVM = FormViewModel()
    var body: some View {
        DetailView(entity: formVM.entity)
    }
}
struct DetailView: View {
    @ObservedObject var entity: Entity
    @State private var localEnabled: Bool = true
    var body: some View {
        Toggle("本地切换", isOn: $localEnabled)
            .onChange(of: localEnabled) { entity.enabled = $0 }
        Toggle("切换", isOn: $entity.enabled)
    }
}
英文:
Because NSManagedObject is reference type.
There is a simple rule:
@Stateand@Bindingis for value types like structs.@StateObjectand@ObservedObjectis for reference types like classes.
And the dollar-sign reference is also only for value types.
Fortunately NSManagedObject conforms to ObservableObjectby default.
struct MainView: View {
    @StateObject private var formVM = FormViewModel()
    var body: some View {
        DetailView(entity: formVM.entity)
    }
}
struct DetailView: View {
    @ObservedObject var entity: Entity
    @State private var localEnabled: Bool = true
    var body: some View {
        Toggle("Local Toggle", isOn: $localEnabled)
            .onChange(of: localEnabled) { entity.enabled = $0 }
        Toggle("Toggle", isOn: $entity.enabled)
    }
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论