swiftui - @published 不适用于类型数组,但适用于单一类型
问题描述
我正在测试非常简单的代码,有一个确认@ObservableObject
协议的类,并且有两个@Published
属性,一个是我的自定义type
对象的数组,另一个只是type
同一类的普通。我有两种观点,其中 parent 拥有单一事实来源,它有 aList
和 a navigationLink
。NavigationLink 将@Published
数组对象传递Binding
给子视图。
问题-:
当我输入时TextField
,视图没有更新。它正在修改@Published
对象属性,但不更新子视图。这仅在我测试Array
对象时发生,但现在如果我评论array
对象属性并简单地使用另一个(没有数组),它会更新得很好。
谁能解释背后的原因,这是一个错误吗?还是Array
在幕后做其他事情?
不工作的例子-:
import SwiftUI
struct Person: Identifiable {
let id: String = UUID().uuidString
var name: String = "Tushar"
var age: Int = 25
init(name: String,age: Int) {
self.name = name
self.age = age
}
}
class PersonStore: ObservableObject {
@Published var name: [Person] = [Person(name:"foo",age:23),Person(name:"foobar",age:23)]
//@Published var name: Person = Person(name:"foo",age:23)
}
struct ContentViewsss: View {
@ObservedObject var store = PersonStore()
@State var isEditing = false
var body: some View {
NavigationView{
List(store.name.indices){ index in
NavigationLink(destination: ContentViewsss1(store: $store.name[index])) {
Text("Edit")
}
}.navigationTitle(“Welcome")
}
}
}
struct ContentViewsss1: View {
@Binding var store: Person
var body: some View {
TextField("My Text", text: $store.name)
Text(store.name)
}
}
工作示例-:
import SwiftUI
struct Person: Identifiable {
let id: String = UUID().uuidString
var name: String = "Tushar"
var age: Int = 25
init(name: String,age: Int) {
self.name = name
self.age = age
}
}
class PersonStore: ObservableObject {
// @Published var name: [Person] = [Person(name:"foo",age:23),Person(name:"foobar",age:23)]
@Published var name: Person = Person(name:"foo",age:23)
}
struct ContentViewsss: View {
@ObservedObject var store = PersonStore()
@State var isEditing = false
var body: some View {
NavigationView{
List{
NavigationLink(destination: ContentViewsss1(store: $store.name)) {
Text("Edit")
}
}.navigationTitle("Welcome")
}
}
}
struct ContentViewsss1: View {
@Binding var store: Person
var body: some View {
TextField("My Text", text: $store.name)
Text(store.name)
}
}
解决方案
据说,导致问题的不是数组——而是List
. 您会在原始代码中看到这一点,如果您将 更改List
为ForEach
,它将起作用。我不确定故障发生在哪里,而且它比人们想象的还要微妙。
我的建议是使用中间视图模型。以下代码有效:
class ViewModel: ObservableObject {
@Published var person : Person {
didSet {
binding.wrappedValue = person
}
}
var binding : Binding<Person>
init(withPersonBinding person: Binding<Person>) {
self.person = person.wrappedValue
self.binding = person
}
}
struct ContentViewsss1: View {
//@Binding var store: Person
@ObservedObject var store : ViewModel
var body: some View {
TextField("My Text", text: $store.person.name)
Text(store.person.name)
}
}
像这样调用它:
NavigationLink(destination: ContentViewsss1(store: ViewModel(withPersonBinding: $store.name[index]))) {
Text("Edit")
}
现在,这是真正奇怪的一点。如果您返回原始代码并将详细视图修改为:
struct ContentViewsss1: View {
@Binding var store: Person
@State private var txt = ""
var body: some View {
TextField("My Text", text: $store.name)
Text(store.name)
TextField("Other text", text: $txt)
}
}
您会看到,如果您编辑第一个文本字段,您的更改将不会被反映(正如您所经历的那样)。但是,一旦您更改第二个字段中的文本,@State 中的更改就会触发它同时检查@Binding,并且该字段会更新。再一次,只发生在List
而不是ForEach
。SwiftUI 的奥秘……
推荐阅读
- reactjs - react-google-maps 中的替代路线
- java - 我在 tomcat7 服务器中有一个端口问题 在 http://localhost:8080/ 上运行战争,但使用 maven 项目的实际端口是 8090
- php - PHP & MySQL - 未定义索引:尝试使用 PHP 进行小查询时的 VIN
- python - 使用 GPU 构建的 TensorFlow 1.8 Cmake 在 Windows 10 上失败并出现 MSB6006 错误
- xslt - XSLT 按名称和总和值分组
- angular6 - 可以激活问题
- linux - 如何将远程 tarball 提取到本地计算机上
- python-3.x - 我无法在 Kivy 应用程序上校准电阻式触摸屏的正确精度
- laravel-5 - 如何从多个下拉列表中选择数据并将它们组合成 laravel 中的一个变量?
- apache-kafka - 配置 ACL 后 Kafka Leader 不可用