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