在 SwiftUI 中设置视图的 ViewModel 的最佳方法是什么

ali*_*ego 2 xcode ios swift swiftui

我是 MVVM 世界的新手,想知道在呈现新视图时设置该视图的 ViewModel 属性的最佳方法是什么?

我尝试在呈现视图的 .fullScreenCover 中初始化 ViewModel 类,但这给我带来了各种各样的问题。这就是我所做的:

struct FirstView: View {
    @State var isActive = false
    var body: some View {
        Text("Tap here to go to SecondView")
            .onTapGesture {
                isActive = true
            }
            .fullScreenCover(isPresented: $isActive, content: {
                SecondView(viewModel: ViewModel(), isActive: $isActive)
            })
    }
    
}
struct SecondView: View {
    @ObservedObject var viewModel: ViewModel
    
    @Binding var isActive: Bool
    
    init(viewModel: ViewModel, isActive: Binding<Bool>) {
        self.viewModel = viewModel
        self._isActive = isActive
    }
    
    var body: some View {
        Button(action: {
            $isActive = false
        }, label: {
            Text("Go back to FirstView")
        })
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是 viewModel 的 init 方法被调用了很多次。我不确定这是否是因为底层 FirstView 正在被重绘,尽管不再显示在屏幕上,或者是否与 SecondView 中访问的绑定 isActive var 有关。无论如何,都会创建如此多的 viewModel。我不知道这是为什么。但更重要的是我想知道初始化新视图的 viewModel 的正确方法是什么。

我目前正在做的是在 FirstView 的 viewModel 中创建 SecondView 的 viewModel 并传递引用,但这感觉非常错误。

nic*_*rno 7

一般来说,您应该@StateObject在初始化ViewModel. 如果您只需要在 中SecondView,那么您不需要将它从 传递FirstViewSecondView,您可以在 中初始化它SecondView

struct SecondView: View {
    @StateObject var viewModel: ViewModel = ViewModel()
Run Code Online (Sandbox Code Playgroud)

但是,如果您需要在第一个视图中引用它,或者您希望无论创建 SecondView 如何保留它,那么您可以FirstView使用以下方法在父视图(在本例中)中初始化它:

 @StateObject var viewModel = ViewModel()
Run Code Online (Sandbox Code Playgroud)

然后将该对象传递给子视图 ( SecondView):

SecondView(viewModel: viewModel...
Run Code Online (Sandbox Code Playgroud)

正如您已经拥有的那样,它应该位于@ObservedObject子视图中:

 @ObservedObject var viewModel: ViewModel
Run Code Online (Sandbox Code Playgroud)

或者,您可以将其初始化为 an@EnvironmentObject并将其传递到环境中,而不是通过初始化器直接将其从视图传递到视图。


我发现很多人都遇到了这个问题,所以如果你想更好地理解,我制作了一些 YouTube 教程:

如何使用@StateObject和@ObservableObject

如何使用@EnvironmentObject

带有 MVVM 的 SwiftUI Todo 应用程序