nde*_*nde 11 ios swift swiftui
我正在尝试在 SwiftUI 应用程序中使用 MVVM,但是似乎每当父子视图都更新时,子视图的视图模型(例如 a 中的视图模型NavigationLink)会重新初始化ObservableObject。这会导致孩子的本地状态被重置,网络数据被重新加载等。
我猜这是因为这会导致body重新评估parent 的值,其中包含一个 toSubView的视图模型的构造函数,但我一直无法找到替代方法来让我创建不会超出生命周期的视图模型看法。我需要能够将数据从父视图传递给子视图模型。
这是我们试图完成的一个非常简化的操场,在那里递增EnvCounter.counterresets 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())
Run Code Online (Sandbox Code Playgroud)
小智 7
一个新的属性包装被添加到SwiftUI在Xcode 12 @StateObject。您应该能够通过简单地改变来解决它@ObservedObject的@StateObject如下。
struct SubView: View {
class ViewModel: ObservableObject {
@Published var counter = 0
}
@EnvironmentObject var envCounter: EnvCounter
@StateObject var viewModel: ViewModel // change on this line
var body: some View {
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
为了解决这个问题,我创建了一个名为ViewModelProvider.
提供程序为您的视图获取一个哈希值,以及一个构建 ViewModel 的方法。然后它要么返回 ViewModel,要么在它第一次收到该散列时构建它。
只要您确保只要您想要相同的 ViewModel,哈希值就保持不变,这就解决了问题。
class ViewModelProvider {
private static var viewModelStore = [String:Any]()
static func makeViewModel<VM>(forHash hash: String, usingBuilder builder: () -> VM) -> VM {
if let vm = viewModelStore[hash] as? VM {
return vm
} else {
let vm = builder()
viewModelStore[hash] = vm
return vm
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后在您的视图中,您可以使用 ViewModel:
Struct MyView: View {
@ObservedObject var viewModel: MyViewModel
public init(thisParameterDoesntChangeVM: String, thisParameterChangesVM: String) {
self.viewModel = ViewModelProvider.makeViewModel(forHash: thisParameterChangesVM) {
MOFOnboardingFlowViewModel(
pages: pages,
baseStyleConfig: style,
buttonConfig: buttonConfig,
onFinish: onFinish
)
}
}
}
Run Code Online (Sandbox Code Playgroud)
在这个例子中,有两个参数。仅thisParameterChangesVM用于散列。这意味着即使thisParameterDoesntChangeVM更改并重新构建视图,视图模型也保持不变。
| 归档时间: |
|
| 查看次数: |
2837 次 |
| 最近记录: |