【问题标题】:Why is SwiftUI Binding for an array instance var not working?为什么数组实例 var 的 SwiftUI 绑定不起作用?
【发布时间】:2021-06-07 18:52:45
【问题描述】:

绑定的行为不像预期的那样,并且 我希望能深入了解正在发生的事情。

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

这段代码应该在原始数组上运行,因为它是 使用绑定,但显然这不是正在发生的事情。有什么想法吗?

如果根对象是名称的@State var,它会按预期工作(请参阅 注释掉的代码)而不是项目的属性。

在 Swift 5 中使用 Xcode 12.4

@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)
    }
}

【问题讨论】:

  • 第一件事不要将状态包装器与类一起使用。另一件事@bindings 用于视图,标记您的 [String] 已发布。从 state 到 StateObject 的主要变化
  • @TusharSharma,如果我不使用状态,如何使用 $ 传递绑定?
  • 查看@jnpdx的答案

标签: swiftui binding observableobject


【解决方案1】:

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

更常见的模型是将状态保存在 ObservableObject 中,该对象归父视图所有:

@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 属性。

【讨论】:

  • 我同意所有这些,除了我会将 ObservedObject 设为父视图中的 StateObject。 StateObject 相当于类的状态,尤其是对于拥有其他希望使用该数据的视图的视图。
  • @jnpdx,感谢您的建议。它可以工作,但我想要做的是有一个模型对象,它是一个类(有几个原因,包括它更容易与核心数据一起使用)——这就是我有一个“项目”类的原因。 ViewModel 对象 ProjectVM 用于使用绑定仅访问“名称”实例 var,以便其对应的 View 可以在该数组上进行操作。我似乎无法让它发挥作用。
  • 我明白了。 CoreData 有很多方便的方法和内置的属性包装器来帮助你在 SwiftUI 中使用它。尝试将 CoreData 包装在其他 ObservableObjects 中并将它们与 Binding/Published 一起使用(与结构一起使用效果更好)可能是一场艰苦的战斗。
  • 偶然发现并提醒您的问题:donnywals.com/…
  • @jnpdx,感谢您的指点。我去看看。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-26
  • 2015-03-21
  • 2021-07-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多