【问题标题】:How to initialize StateObject within SwiftUI with parameter如何在 SwiftUI 中使用参数初始化 StateObject
【发布时间】:2021-09-30 05:24:12
【问题描述】:

我正在开发一个使用 MVVM 架构的 SwiftUI 应用程序。我有一个问题,我需要将数据从父视图传递到其子视图模型,但我不确定如何将视图中的参数传递到视图模型。

应该拥有 viewModel 的子 View 在这里:

struct InstanceView: View {
    @ObservedObject var instance: Instance
    
    @StateObject var viewModel = InstanceViewViewModel(instance: instance)

    var body: some View {
        ...
    }
}

这是视图模型:

class InstanceViewViewModel: ObservableObject {
    @ObservedObject var instance: Instance
    
    ...
}

显然视图不起作用,我收到错误Cannot use instance member 'instance' within property initializer; property initializers run before 'self' is available

如果我尝试在视图中使用init()viewModel 赋值:

@ObservedObject var instance: Instance

@StateObject var viewModel: InstanceViewViewModel

init(instance: Instance) {
    self.instance = instance
    self.viewModel = InstanceViewViewModel(instance: instance)
}

但我收到错误 Cannot assign to property: 'viewModel' is a get-only property

我读到你应该给 viewModel 属性 (instance) 一个默认值,然后在视图中用.onAppear() 设置它。但是,就我而言,Instance 是一个 Core Data 对象,所以我无法真正创建一个用作默认值。

我还读到我可以在 View 的 init 中使用 _instance = StateObject(wrappedValue: InstanceViewViewModel(instance: instance)),而 swiftUI 将足够聪明,只需初始化一次 StateObject。但是我很确定这是一种不好的做法。

我也不能在StateObject 上使用lazy

那么还有其他方法可以实现吗?解决方案是否可以通过某种方式获取 InstanceView 正在这一行初始化的值:

@StateObject var viewModel = InstanceViewViewModel(instance: instance)

,在 init 之外,所以我不需要像在 init 内部那样引用 self? (这可能是个愚蠢的想法)

或者我应该以不同的方式实现 MVVM?

谢谢!

【问题讨论】:

  • 是的,您应该以不同的方式实现 MVVM。 viewModel 是您的事实来源,它应该独立于视图。您尝试使用什么参数对其进行初始化?
  • “但是我很确定这是一个不好的做法。” - 为什么?就像您提到的那样,StateObject 在创建过程中使用了自动关闭,因此它只会创建一次(在我今年夏天的 WWDC 实验室中确认)。使用 initonAppear 是 SwiftUI 工程师向我推荐的。
  • ObservableObject 中存储@ObservedObject 没有意义。也许你的意思是@Published
  • 这可能会有所帮助stackoverflow.com/a/68480486/14733292
  • 这是否回答了您的问题stackoverflow.com/a/62636048/12299030

标签: swift mvvm swiftui combine observableobject


【解决方案1】:

你不应该在 SwiftUI 中使用 MVVM 模式,因为它不兼容。在 SwiftUI 中,视图结构保存数据,因此您可以将它们视为等同于视图模型,但在 SwiftUI 中,结构的使用提供了值语义的优势,从而为我们提供了一致性和速度。这些结构形成一个有效更新(通过依赖跟踪)和差异层次结构,SwiftUI 在内部获取结果,它们以特定于平台的方式为我们更新 UIKit(或 AppKit)控件,我们不与视图对象交互,(V在传统的 MVC/MVVM 意义上)。在 SwiftUI 中,我们尽可能避免使用对象,因为我们希望使用堆栈来提高速度并避免使用堆。最后,引用类型的“ObservableObject”协议是组合框架的一部分,因此我们仅在需要组合管道时才使用它,而在您的情况下似乎不需要。 ‘@StateObject’ 定义了一个真实的来源,因此它不可能接受任何参数,因为那样它就不是真实的来源。

【讨论】:

    【解决方案2】:

    SwiftUI 属性包装器通常是自动的。 @StateObject 以初始化必须在声明点的方式修改属性。模式suggested by Apple 是在视图的父级中创建@StateObject 并将其作为@ObservedObject@EnvironmentObject 向下传递。

    【讨论】:

      猜你喜欢
      • 2021-12-20
      • 2022-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-16
      相关资源
      最近更新 更多