0

我的代码刚刚遇到一个不幸的问题:

class MyViewModel: ObservableObject {
    func load() {
        // set up Combine subscriptions, etc.
    }
}

struct MyView: View {
    @ObservedObject private var viewModel = MyViewModel()

    var body: some View {
        SomeChildView()
            .onAppear { self.viewModel.load() }
    }
}

我有很多以这种方式构建的视图。(一些)状态和逻辑被卸载到一个视图模型,该模型在onAppear.

问题是视图可能会被重新渲染,但onAppear只执行一次。结果是,只要视图被重新渲染一次或多次,视图模型中的任何状态都不会真正反映在视图中,因为只有第一个实例load()调用了它的方法。

有几种方法可以解决这个问题,但它们都有缺点:

  • 我可以将逻辑load()移到中init(),但这似乎很臭,因为init()它是用于属性分配等简单的事情,而不是用于设置订阅或其他外部访问。此外,我希望能够覆盖用于测试的视图模型逻辑,并且init()不能被覆盖。编辑:这里更大的问题是我们只想在视图出现时执行一次加载逻辑,而不是每次视图呈现时。
  • 我可以从父级传递视图模型,但是如果重新渲染父级,则可能会遇到同样的问题。
  • 我可以初始化视图模型SceneDelegate并将其作为@EnvironmentObject. .

我觉得有一种简单的方法可以实现我只是想念的。跳出框框思考,我使用视图模型的原因是为了分离关注点和便于单元测试。我希望视图只与视图模型提供的接口进行交互,而视图模型可以处理所有杂乱的数据访问。我也不确定是否有另一种方法可以在Publisher不使用ObservableObject.

4

1 回答 1

1

不确定我是否理解您的问题,但对于您列表中的第二个选项,有一种方法可以确保重新渲染父级不会破坏数据 - 您可以在那里使用 @StateObject 而不是 @ObservedObject :

@StateObject private var viewModel = MyViewModel()

然后将其传递给孩子的 @ObservedObject 属性

于 2021-12-20T16:38:57.567 回答