SwiftUI 构造一个视图树View
对象在body
他们的父母。
所以,SwiftUI 得到的是最初的copy(记住,这是一个值类型struct
) of myKeyboard
,而不是您要更改的副本。
在正常使用情况下,您不会将各种 View 的实例存储为变量(我的意思是,您可以,但您需要深入了解发生了什么)。
您可能想要的是更改驱动子视图的数据。这些数据(应该)存放在哪里?这取决于你想做什么。
在大多数情况下,父级“拥有”状态,即拥有子级所依赖的某些数据的真实来源。然后更改状态并通过其将状态传递给子级就很简单了init
:
struct ChildView: View {
let number: Int
var body: some View {
Text("\(number)")
}
}
struct ParentView: View {
@State var random: Int = Int.random(1...100)
var body: some View {
VStack() {
ChildView(number: random)
Button("randomize") {
self.random = Int.random(1...100)
}
}
}
}
但是,比如说,父母不想进行随机化——即孩子应该处理它。
正确的方法是为子级创建一个视图模型,父级(或父级自己的视图模型)可以拥有并通过init
,然后视图模型将处理随机化的细微差别。
class ChildVM: ObservableObject {
@Published var random = Int.random(1...100)
func change() {
random = Int.random(1...100)
}
}
父级创建一个实例ChildVM
并将其传递给孩子:
struct ParentVuew: View {
let childVM = ChildVM()
var body: some View {
VStack() {
ChildView(vm: childVm)
Button("randomize") {
self.childVM.change()
}
}
}
}
子视图只是由视图模型驱动:
struct ChildView: View {
@ObservedObject let vm: ChildVM
var body: some View {
Text("\(vm.random)")
}
}
显然,这是一个可以通过多种方式实现的简化示例。
父母可以通过不同的方式向孩子“发送消息”。
但一般的结论应该是View
应该被认为是声明性结构——而不是活的实例——而数据是驱动这些视图变化的因素。您需要决定谁最能拥有真相来源。