我将新 @Observable
宏用于我的 ViewModel。该类如下所示
@Observable
class TransitiveModel {
private var strings: [String] = []
func getStrings() -> [String] {
return strings
}
func addString(_ item: String) {
strings.append(item)
}
}
这是对我实际类的简化,但它可以作为最低限度的示例。您可能会争辩说,在这个例子中可能不需要 getStrings() 方法,但是在我的实际类中,我之前传递了参数并进行了一些计算,所以请假装它很重要。
我有一个简单的观点
private var model = TransitiveModel()
var body: some View {
VStack {
ForEach(model.getStrings(), id: \.self) { item in
Text(item)
}
Button("Add Item") {
model.addString("Hello")
}
}
}
当我按下按钮时,我预计视觉上不会有任何变化,因为我没有直接订阅strings
视图中的数组。然而,我观察到视图无论如何都会更新,很可能是因为getStrings()
依赖于已更改的数组。我不想依赖这种行为,除非我确定它是正确的,而不是故障或类似的东西。我认为更改strings
将触发再次调用该函数,对吗?是否有某种文档可以帮助我理解它?
即使您不“直接”访问
@Observable
属性,SwiftUI 仍可以找到视图的依赖项。只要@Observable
在执行期间调用属性的 getter/setterView.body
,就会发现该属性是该视图的依赖项。这是因为
@Observable
宏在这些属性的 getter/setter 中生成额外的代码,以将这些属性的访问/变异注册到观察注册器中,然后 SwiftUI 使用该注册器来跟踪依赖项。生成的代码不会查看调用堆栈,并会说“这不是直接调用的,
View.body
所以我不会注册此访问”。毕竟,Observation 不应该与 SwiftUI 紧密耦合。既然相反的做法通常更可取,为什么它要做这些额外的工作呢?对于文档,我首先想到的是 WWDC 上的两个视频:在 SwiftUI 中发现观察 (Discover Observation in SwiftUI),其中解释了观察的工作原理;以及揭开 SwiftUI 的神秘面纱 (Demystifying SwiftUI ),其中讨论了视图的“依赖关系”是什么。
至于评论中的问题:
是的。由于 的 getter
strings
是在 中调用的body
,因此无论从何处调用 的 setterstrings
,SwiftUI 视图都会更新。如果您不希望视图
models.strings
因某种原因发生变化时在视觉上发生变化,您可以添加一个额外的内容@State
来单独存储字符串。这@State
将独立于model.strings
。