SwiftUI视图在@Binding属性未被修改时被重新初始化



我正在执行一个包含2个标签和2个修改这些标签值的按钮的SwiftUI游乐场。

我已经将这些标签的值存储在@ObservableObject中。当我修改这些属性的值时,视图CustomText2CustomText3被重新初始化,即使他的值没有改变。

代码:

final class ViewModel: ObservableObject {
@Published var title: Int
@Published var title2: Int
init(title: Int = 0, title2: Int = 0) {
self.title = title
self.title2 = title2
}
}
struct ContentView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
VStack {
Button(
action: {
viewModel.title += 1
}, label: {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
}
)
CustomText1(
title: $viewModel.title
)
Button(
action: {
viewModel.title2 += 1
}, label: {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
}
)
CustomText2(
title: $viewModel.title2
)
}
.padding()
}
}
struct CustomText1: View {
@Binding var title: Int
init(
title: Binding<Int>
) {
self._title = title
}
var body: some View {
Text("(title)")
.foregroundColor(.black)
}
}

但是,如果我在视图中存储@State属性并修改它们,CustomTexts不会重新初始化,它们只是在不执行init的情况下更新它们在主体中的值。

为什么当我在ViewModel中存储两个属性时,它们会被重新初始化?

我已经尝试使视图符合Equatable,但他们被重新初始化。如果视图被初始化多次,可能会出现性能问题?

我不想让子视图重新初始化,因为我想在一些子视图的初始化中执行自定义的东西。

当你有一个StateObject包含多个状态变量,更改其中一个将重新绘制整个视图。在你的例子中,对viewModel中的任何变量的任何更改都将触发viewModel的发布者并重新加载ContentView

我们也不应该对视图何时被重绘做出任何假设,因为这可能会随着不同版本的SwiftUI而改变。最好把你在视图的init中做的这些自定义的东西移到其他地方(如果可以的话)。Init应该只做用新的状态参数重新绘制视图所需的工作,而不做其他工作。

@ObservableObject用于模型数据,而不是视图数据。

原因是当使用let或@State变量时,SwiftUI使用依赖跟踪来决定是否需要调用body,而在你的情况下,body不会在任何地方使用这些值,所以没有必要调用它。

它不能以同样的方式跟踪对象,如果声明了@StateObject,那么不管是否访问了任何属性,都将调用body,所以最好从@State值类型开始,只有在真正需要引用类型的特性时才更改为@StateObject。现在我们不经常使用。task,这是放置自定义异步工作的地方。

最新更新