如何在模型类子属性更改时促使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()没有成功,但看起来我没有跟上当前语法。对于任何重新创建我的代码的人来说,值得注意的是,在类版本中,您需要更改结果数组的创建以不使用重复初始化器–数组中的所有对象都将指向同一实例!