为什么我的SwiftUI应用程序中未更新ObservedObject数组?

为什么我的SwiftUI应用程序中未更新ObservedObject数组?,swiftui,Swiftui,我在玩SwitUI,试图了解ObservieObject是如何工作的。我有一个Person对象数组。当我向数组中添加一个新人时,它会在我的视图中重新加载。但是,如果更改现有人员的值,则不会在视图中重新加载该人员 // NamesClass.swift import Foundation import SwiftUI import Combine class Person: ObservableObject,Identifiable{ var id: Int @Publishe

我在玩SwitUI,试图了解ObservieObject是如何工作的。我有一个Person对象数组。当我向数组中添加一个新人时,它会在我的视图中重新加载。但是,如果更改现有人员的值,则不会在视图中重新加载该人员

//  NamesClass.swift
import Foundation
import SwiftUI
import Combine

class Person: ObservableObject,Identifiable{
    var id: Int
    @Published var name: String

    init(id: Int, name: String){
        self.id = id
        self.name = name
    }

}

class People: ObservableObject{
    @Published var people: [Person]

    init(){
        self.people = [
            Person(id: 1, name:"Javier"),
            Person(id: 2, name:"Juan"),
            Person(id: 3, name:"Pedro"),
            Person(id: 4, name:"Luis")]
    }

}
如果我取消对行的注释以添加一个新人(John),Jaime的名字将正确显示。但是,如果我只是更改名称,则不会在视图中显示

恐怕我做错了什么,或者我不明白被观测对象是如何使用数组的


欢迎任何帮助或解释

您可以使用结构而不是类。由于结构的值语义,对人名的更改被视为对person结构本身的更改,并且此更改也是对people数组的更改,因此@Published将发送通知并重新计算视图主体

<代码>导入基础 导入快捷键 进口联合收割机 结构人:可识别{ 变量id:Int 变量名称:String init(id:Int,name:String){ self.id=id self.name=名称 } } 类模型:ObservieObject{ @已发布个人:[个人] init(){ self.people=[ 此人(身份证号码:1,姓名:“Javier”), 此人(身份证号码:2,姓名:“Juan”), 此人(身份证号码:3,姓名:“佩德罗”), 个人(身份证号码:4,姓名:“路易斯”)] } } 结构ContentView:View{ @StateObject变量模型=模型() var body:一些观点{ VStack{ ForEach(model.people){person in 文本(“\(person.name)”) } 按钮(操作:{ self.mypeople.people[0]。name=“Jaime” }) { 文本(“添加/更改名称”) } } } } 或者(不推荐),
Person
是一个类,因此它是一个引用类型。当它改变时,
People
数组保持不变,因此主体不会发出任何信息。但是,您可以手动调用它,让它知道:

按钮(操作:{
self.mypeople.objectWillChange.send()
self.mypeople.people[0]。name=“Jaime”
}) {
文本(“添加/更改名称”)
}

对于那些可能觉得它有用的人。这是对@kontiki的答案的更一般的方法

这样,您就不必为不同的模型类类型重复自己的操作了

import Foundation
import Combine
import SwiftUI

class ObservableArray<T>: ObservableObject {

    @Published var array:[T] = []
    var cancellables = [AnyCancellable]()

    init(array: [T]) {
        self.array = array

    }

    func observeChildrenChanges<T: ObservableObject>() -> ObservableArray<T> {
        let array2 = array as! [T]
        array2.forEach({
            let c = $0.objectWillChange.sink(receiveValue: { _ in self.objectWillChange.send() })

            // Important: You have to keep the returned value allocated,
            // otherwise the sink subscription gets cancelled
            self.cancellables.append(c)
        })
        return self as! ObservableArray<T>
    }


}

class Person: ObservableObject,Identifiable{
    var id: Int
    @Published var name: String

    init(id: Int, name: String){
        self.id = id
        self.name = name
    }

} 

struct ContentView : View {
    //For observing changes to the array only. 
    //No need for model class(in this case Person) to conform to ObservabeObject protocol
    @ObservedObject var mypeople: ObservableArray<Person> = ObservableArray(array: [
            Person(id: 1, name:"Javier"),
            Person(id: 2, name:"Juan"),
            Person(id: 3, name:"Pedro"),
            Person(id: 4, name:"Luis")])

    //For observing changes to the array and changes inside its children
    //Note: The model class(in this case Person) must conform to ObservableObject protocol
    @ObservedObject var mypeople: ObservableArray<Person> = try! ObservableArray(array: [
            Person(id: 1, name:"Javier"),
            Person(id: 2, name:"Juan"),
            Person(id: 3, name:"Pedro"),
            Person(id: 4, name:"Luis")]).observeChildrenChanges()

    var body: some View {
        VStack{
            ForEach(mypeople.array){ person in
                Text("\(person.name)")
            }
            Button(action: {
                self.mypeople.array[0].name="Jaime"
                //self.mypeople.people.append(Person(id: 5, name: "John"))
            }) {
                Text("Add/Change name")
            }
        }
    }
}

<代码>导入基础 进口联合收割机 导入快捷键 类ObservalArray:ObservaleObject{ @已发布的变量数组:[T]=[] var cancelables=[anycancelables]() init(数组:[T]){ self.array=array } func observeChildrenChanges()->observeArray{ 设array2=数组为![T] 阿雷亚弗雷奇({ 设c=$0.objectWillChange.sink(self.objectWillChange.send()中的receiveValue:{uu}) //重要提示:您必须保留已分配的返回值, //否则,接收器订阅将被取消 self.cancelables.append(c) }) 返回自我为!可观察到的 } } 类人:可观察对象,可识别{ 变量id:Int @已发布变量名称:String init(id:Int,name:String){ self.id=id self.name=名称 } } 结构ContentView:View{ //仅用于观察阵列的更改。 //模型类(在本例中为Person)不需要符合ObservabeObject协议 @ObservedObject变量mypeople:ObservableArray=ObservableArray(数组:[ 此人(身份证号码:1,姓名:“Javier”), 此人(身份证号码:2,姓名:“Juan”), 此人(身份证号码:3,姓名:“佩德罗”), 个人(身份证号码:4,姓名:“路易斯”)]) //用于观察阵列的更改及其子级内部的更改 //注意:模型类(在本例中为Person)必须符合ObserveObject协议 @ObservedObject var mypeople:ObservableArray=try!ObservableArray(数组:[ 此人(身份证号码:1,姓名:“Javier”), 此人(身份证号码:2,姓名:“Juan”), 此人(身份证号码:3,姓名:“佩德罗”), 个人(id:4,姓名:“Luis”)]) var body:一些观点{ VStack{ ForEach(mypeople.array){person in 文本(“\(person.name)”) } 按钮(操作:{ self.mypeople.array[0]。name=“Jaime” //self.mypeople.people.append(个人(id:5,姓名:“John”)) }) { 文本(“添加/更改名称”) } } } }
我认为这个问题有一个更优雅的解决方案。您可以为列表行创建自定义视图,以使每个项都是@ObservedObject,而不是尝试将
objectWillChange
消息传播到模型层次结构中:

struct PersonRow: View {
    @ObservedObject var person: Person

    var body: some View {
        Text(person.name)
    }
}

struct ContentView: View {
    @ObservedObject var mypeople: People

    var body: some View {
        VStack{
            ForEach(mypeople.people){ person in
                PersonRow(person: person)
            }
            Button(action: {
                self.mypeople.people[0].name="Jaime"
                //self.mypeople.people.append(Person(id: 5, name: "John"))
            }) {
                Text("Add/Change name")
            }
        }
    }
}

通常,为列表/ForEach中的项目创建自定义视图可以监视集合中的每个项目的更改。

ObservalArray非常有用,谢谢!这里有一个更通用的版本,它支持所有集合,当您需要通过对多关系(建模为集合)间接地对CoreData值作出反应时,它非常方便

导入联合收割机
导入快捷键
私有类ObservedObjectCollectionBox:ObserveObject,其中元素:ObserveObject{
私有风险值订阅:是否可取消?
init(wAppedValue:AnyCollection){
自我重置(wrappedValue)
}
func重置(uNewValue:AnyCollection){
self.subscription=publisher.MergeMany(newValue.map{$0.objectWillChange})
.删除任何发布者()
.sink{uuuu in
self.objectWillChange.send()
}
}
}
@房地产经纪人
public struct observedObject集合:DynamicProperty其中元素:observedObject{
公共var wrappedValue:AnyCollection{
迪塞特{
如果已知,则无唯一参考(&观察){
自我观察重置(wrappedValue)
}否则{
自我观察
struct PersonRow: View {
    @ObservedObject var person: Person

    var body: some View {
        Text(person.name)
    }
}

struct ContentView: View {
    @ObservedObject var mypeople: People

    var body: some View {
        VStack{
            ForEach(mypeople.people){ person in
                PersonRow(person: person)
            }
            Button(action: {
                self.mypeople.people[0].name="Jaime"
                //self.mypeople.people.append(Person(id: 5, name: "John"))
            }) {
                Text("Add/Change name")
            }
        }
    }
}