首页 > 解决方案 > @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)
    }
}

标签: swiftuiswiftui-navigationlinkobservableobject

解决方案


据说,导致问题的不是数组——而是List. 您会在原始代码中看到这一点,如果您将 更改ListForEach,它将起作用。我不确定故障发生在哪里,而且它比人们想象的还要微妙。

我的建议是使用中间视图模型。以下代码有效:

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 的奥秘……


推荐阅读