为什么数组实例变量的SwiftUI绑定不起作用?

为什么数组实例变量的SwiftUI绑定不起作用?,swiftui,binding,observableobject,Swiftui,Binding,Observableobject,绑定的行为与预期的和预期的不一样 我希望能深入了解情况 下面是说明该问题的代码。一个名为“Project”的类模型对象 包含名为“name”的字符串数组。 代码将名称的绑定传递给类型为ProjectVM的ViewModel 在视图中使用。在视图的列表中,我可以删除一行, 对应于删除字符串数组的一个元素, 但它马上又回来了 此代码应该在原始数组上运行,因为它是 使用绑定,但显然不是这样。有什么想法吗 如果根对象是名称的@State变量,则它将按预期工作(请参见 注释掉的代码)而不是项目的属性 使用

绑定的行为与预期的和预期的不一样 我希望能深入了解情况

下面是说明该问题的代码。一个名为“Project”的类模型对象 包含名为“name”的字符串数组。 代码将名称的绑定传递给类型为ProjectVM的ViewModel 在视图中使用。在视图的列表中,我可以删除一行, 对应于删除字符串数组的一个元素, 但它马上又回来了

此代码应该在原始数组上运行,因为它是 使用绑定,但显然不是这样。有什么想法吗

如果根对象是名称的@State变量,则它将按预期工作(请参见 注释掉的代码)而不是项目的属性

使用Xcode 12.4和Swift 5

@main
struct Try_ArrayBindingApp: App {
    @State var project = Project()
    //@State var names = [ "a", "b", "c" ]
    var body: some Scene {
        WindowGroup {
            ProjectV(pVM: ProjectVM(names: $project.names))
            //ProjectV(pVM: ProjectVM(names: $names))
        }
    }
}

class Project { var names = [ "one", "two", "three"] }

class ProjectVM: ObservableObject {
    @Binding var names: [String]
    
    init(names: Binding<[String]> ) { self._names = names }
    
    func delete(at offsets: IndexSet) {
        names.remove(atOffsets: offsets)
    }
}

struct ProjectV: View {
    @ObservedObject var pVM: ProjectVM
    
    var body: some View {
        VStack {
            List {
                ForEach(pVM.names, id: \.self) { n in
                    Text(n)
                }
                .onDelete(perform: delete)
            }
        }
    }
    
    private func delete(at offsets: IndexSet) {
        pVM.delete(at: offsets)
    }
}

@main
结构Try\u ArrayBindingApp:App{
@State var project=project()
//@状态变量名称=[“a”、“b”、“c”]
var body:一些场景{
窗口组{
ProjectV(pVM:ProjectVM(名称:$project.names))
//ProjectV(pVM:ProjectVM(名称:$names))
}
}
}
类项目{var name=[“一”、“二”、“三”]}
ProjectVM类:ObservableObject{
@绑定变量名称:[字符串]
init(names:Binding){self.\u names=names}
func delete(偏移量处:IndexSet){
名称。删除(原子偏移:偏移)
}
}
结构ProjectV:视图{
@观测对象变量pVM:ProjectVM
var body:一些观点{
VStack{
名单{
ForEach(pVM.names,id:\.self){n in
文本(n)
}
.onDelete(执行:删除)
}
}
}
private func delete(偏移量处:IndexSet){
pVM.delete(在:偏移处)
}
}

通过在父视图中保持初始@状态,然后将其@绑定到可观察对象,然后将其发送到子视图,至少数据流肯定会变得混乱。事实上,我并不认为它不应该像你想象的那样,但它是一个令人困惑的思维模式,而不是你在SwiftUI中经常看到的真实的东西

更常见的模型是将状态保存在ObserveObject中,该对象由父视图拥有:

@main
struct Try_ArrayBindingApp: App {
    @StateObject var project = ProjectVM(names: [ "one", "two", "three"])
    var body: some Scene {
        WindowGroup {
          ProjectV(pVM: project)
        }
    }
}

class ProjectVM: ObservableObject {
    @Published var names: [String]
    
    init(names: [String]) {
        self.names = names
    }
    
    func delete(at offsets: IndexSet) {
        names.remove(atOffsets: offsets)
    }
}

struct ProjectV: View {
    @ObservedObject var pVM: ProjectVM
    
    var body: some View {
        VStack {
            List {
                ForEach(pVM.names, id: \.self) { n in
                    Text(n)
                }
                .onDelete(perform: delete)
            }
        }
    }
    
    private func delete(at offsets: IndexSet) {
        pVM.delete(at: offsets)
    }
}


请注意,
names
现在是一个
@Published
属性。

首先不要将状态包装器用于类。另一件事@bindings用于视图,请将[String]标记为Published。主要是从州到州的转变StateObject@TusharSharma,如果不使用state,如何使用$传递绑定?请检查@jnpdxI的答案是否同意所有这些,除非我将ObservedObject设置为父视图中的StateObject。StateObject相当于类的状态,尤其是对于拥有希望使用该数据的其他视图的视图。@jnpdx,谢谢您的建议。它是可行的,但我尝试做的是让一个模型对象成为一个类(有几个原因,包括它更容易与核心数据一起使用)——这就是为什么我有一个“项目”类。ViewModel对象ProjectVM用于使用绑定仅访问“names”实例变量,以便其对应的视图可以在该数组上操作。看来我没法让它发挥作用,我明白了。CoreData内置了许多方便的方法和属性包装器,可以帮助您在SwiftUI中使用它。试图将CoreData包装到其他ObserveObject中,并将其用于绑定/发布(这在结构中确实能更好地工作)可能是一场艰苦的战斗。遇到了这一点,并提醒了您的问题:@jnpdx,感谢您的指针。我去看看。