首页 > 解决方案 > SwiftUI MVVM:父视图更新时重新初始化子视图模型

问题描述

我正在尝试在 SwiftUI 应用程序中使用 MVVM,但是似乎NavigationLink每当父子视图都被更新时,子视图的视图模型(例如 a 中的视图模型)都会重新初始化ObservableObject。这会导致孩子的本地状态被重置,网络数据被重新加载等。

我猜这是因为这会导致body重新评估父级,其中包含SubView视图模型的构造函数,但我无法找到一个替代方案,让我创建不会超出生命周期的视图模型看法。我需要能够将数据从父视图模型传递给子视图模型。

这是我们试图完成的一个非常简化的操场,其中递增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())

标签: iosswiftswiftui

解决方案


Xcode 12 中的 SwiftUI 中添加了一个新的属性包装器,@StateObject. 您应该能够通过简单地更改@ObservedObjectfor来修复它,@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 {
        // ...
    }
}

推荐阅读