我试图在SwiftUI app中使用MVVM,但似乎子视图(例如NavigationLink
中的视图模型)每当一个被父视图和子视图都观察的ObservableObject
被更新时就会重新初始化。这会导致重置子视图的本地状态、重新加载网络数据等。
我猜测这是因为这会导致父视图的body
重新评估,其中包含构造SubView
的视图模型的构造函数,但我找不到任何替代方案,可以让我创建不会超出视图生命周期的视图模型。我需要能够从父视图向子视图模型传递数据。
以下是我们尝试完成的非常简化的示例代码,在其中增加EnvCounter.counter
将重置SubView.counter
。
import SwiftUI
import PlaygroundSupport
class EnvCounter: ObservableObject {
@Published var counter = 0
}
struct ContentView: View {
@ObservedObject var envCounter = EnvCounter()
var body: some View {
VStack {
Text("Parent view")
Button(action: { self.envCounter.counter += 1 }) {
Text("EnvCounter is at \(self.envCounter.counter)")
}
.padding(.bottom, 40)
SubView(viewModel: .init())
}
.environmentObject(envCounter)
}
}
struct SubView: View {
class ViewModel: ObservableObject {
@Published var counter = 0
}
@EnvironmentObject var envCounter: EnvCounter
@ObservedObject var viewModel: ViewModel
var body: some View {
VStack {
Text("Sub view")
Button(action: { self.viewModel.counter += 1 }) {
Text("SubView counter is at \(self.viewModel.counter)")
}
Button(action: { self.envCounter.counter += 1 }) {
Text("EnvCounter is at \(self.envCounter.counter)")
}
}
}
}
PlaygroundPage.current.setLiveView(ContentView())
View.body
可计算属性会被调用,因此任何未被内部状态条件隐藏的代码都将被执行,从而调用所有可见视图构造函数。只需不要在视图构造函数和/或属性默认值中放置任何繁重的内容,将所有逻辑移出视图(将获得奖励-快速UI渲染)。 - Asperi