如何在模型类子属性更改时促使SwiftUI视图更新?

如何在模型类子属性更改时促使SwiftUI视图更新?,swiftui,Swiftui,为了更好地理解这一点,我创建了一个简单的项目。代码如下 我有一个数据源(DataSource),其中包含一个@已发布的数组MyObject项MyObject包含一个字符串。按下UI上的按钮会立即更新一个MyObject实例,并在几秒钟后启动计时器更新第二个实例 如果MyObject是一个结构,那么一切都会按照我想象的那样工作。但是如果MyObject是一个类,则不会触发刷新 我的期望是,更改结构的值会导致在数组中放置更改的实例,从而触发更新链。但是,如果MyObject是一个类,那么更改引用类型

为了更好地理解这一点,我创建了一个简单的项目。代码如下

我有一个数据源(
DataSource
),其中包含一个
@已发布的
数组
MyObject
MyObject
包含一个字符串。按下UI上的按钮会立即更新一个
MyObject
实例,并在几秒钟后启动计时器更新第二个实例

如果
MyObject
是一个结构,那么一切都会按照我想象的那样工作。但是如果
MyObject
是一个类,则不会触发刷新

我的期望是,更改结构的值会导致在数组中放置更改的实例,从而触发更新链。但是,如果
MyObject
是一个类,那么更改引用类型中的字符串会在数组中留下相同的实例。Array没有意识到发生了变化,所以没有向我的
数据源提到这一点。没有发生UI更新

所以问题是–当
MyObject
类的属性更改时,需要做什么才能使UI更新?我试图将
MyObject
变成
observeObject
,并加入了一些
didchange.send()
指令,但都没有成功(我相信这些指令现在在任何情况下都是多余的)

有人能告诉我这是否可行,以及如何修改下面的代码来实现这一点吗?如果有人想问我为什么不使用struct,原因是在我的实际项目中,我已经尝试过这样做。但是,我使用的数据类型集合在闭包(集合中每个项的并行处理)和其他环中进行修改。我尝试将它们重新编写为结构,但遇到了很多挑战

import Foundation
import SwiftUI

struct ContentView: View
{
    @ObservedObject var source = DataSource()

    var body: some View
    {
        VStack
        {
            ForEach(0..<5)
            {i in
                HelloView(displayedString: self.source.results[i].label)
            }
            Button(action: {self.source.change()})
            {
                Text("Change me")
            }
        }
    }
}

struct HelloView: View
{
    var displayedString: String

    var body: some View
    {
        Text("\(displayedString)")
    }
}

class MyObject // Works if declared as a Struct
{
    init(label: String)
    {
        self.label = label
    }

    var label: String
}

class DataSource: ObservableObject
{
    @Published var results = [MyObject](repeating: MyObject(label: "test"), count: 5)

    func change()
    {
        print("I've changed")
        results[3].label = "sooner"
        _ = Timer.scheduledTimer(withTimeInterval: 2, repeats: false, block: {_ in self.results[1].label = "Or later"})
    }
}

struct ContentView_Previews: PreviewProvider
{
    static var previews: some View
    {
        ContentView()
    }
}
<代码>导入基础 导入快捷键 结构ContentView:View { @ObservedObject变量源=数据源() var body:一些观点 { VStack {
ForEach(0..当
MyObject
是类类型时,
results
包含引用,因此当您更改
results
中任何实例的属性时,该实例的引用不会更改,因此
results
不会更改,因此不会发布任何内容,也不会更新UI

在这种情况下,解决方案是在执行内部模型的任何更改时显式强制发布

class DataSource: ObservableObject
{
    @Published var results = [MyObject](repeating: MyObject(label: "test"), count: 5)

    func change()
    {
        print("I've changed")
        results[3].label = "sooner"
        self.objectWillChange.send()    // << here !!

        _ = Timer.scheduledTimer(withTimeInterval: 2, repeats: false) {[weak self] _ in
            self?.results[1].label = "Or later"
            self?.objectWillChange.send()            // << here !!
        }
    }
}
类数据源:ObservableObject
{
@已发布的var结果=[MyObject](重复:MyObject(标签:“测试”),计数:5)
func change()
{
打印(“我已更改”)
结果[3]。label=“更早”

self.objectWillChange.send()/当
MyObject
是类类型时,
results
包含引用,因此当您更改
results
中任何实例的属性时,该实例的引用不会更改,因此
results
不会更改,因此不会发布任何内容,也不会更新UI

在这种情况下,解决方案是在执行内部模型的任何更改时显式强制发布

class DataSource: ObservableObject
{
    @Published var results = [MyObject](repeating: MyObject(label: "test"), count: 5)

    func change()
    {
        print("I've changed")
        results[3].label = "sooner"
        self.objectWillChange.send()    // << here !!

        _ = Timer.scheduledTimer(withTimeInterval: 2, repeats: false) {[weak self] _ in
            self?.results[1].label = "Or later"
            self?.objectWillChange.send()            // << here !!
        }
    }
}
类数据源:ObservableObject
{
@已发布的var结果=[MyObject](重复:MyObject(标签:“测试”),计数:5)
func change()
{
打印(“我已更改”)
结果[3]。label=“更早”

self.objectWillChange.send()//非常感谢。我一直在尝试didChange.send())没有成功,但看起来我没有跟上当前语法。对于任何重新创建我的代码的人来说,值得注意的是,在类版本中,您需要更改结果数组的创建,而不是使用重复的初始化器–数组中的所有对象都将指向同一个实例!非常感谢。我一直在尝试didChange.send()没有成功,但看起来我没有跟上当前语法。对于任何重新创建我的代码的人来说,值得注意的是,在类版本中,您需要更改结果数组的创建以不使用重复初始化器–数组中的所有对象都将指向同一实例!