【问题标题】:How to propagate Model changes through ViewModel in SwiftUI?如何在 SwiftUI 中通过 ViewModel 传播模型更改?
【发布时间】:2020-09-10 23:52:36
【问题描述】:

我试图了解 SwiftUI 中的 MVVM 模式,但我不完全了解 ViewModel 如何侦听和传播来自 Model 对象的更改。许多示例,包括来自 Apple 的 this one,都谈到了让模型继承自 ObservableObject 并直接在您的视图中使用它。这是有道理的。

但是,ViewModel 应该观察其底层模型变化的最佳/推荐方式是什么?

一个简单的例子是WidgetView,它显示了一个小部件的title,但是title可以在后台网络调用中在后台发生变化。

class WidgetView: View {
    @ObservedObject var widgetVM = WidgetViewModel()

    var body: some View {
        Text(widgetVM.title)
    }
}

class WidgetViewModel : ObservableObject {
   var widget: Widget

   var title: String {
      get {
         // Some translation to the title for this particular view
         return widget.title + "!"
      }
   }
}

struct Widget {
    // Some other timer or background process is changing the title
    var title: String
}

我探索过的一个粗略的解决方案是拥有一个单独的title 并监听变化。因此,如果Widget 扩展了ObservableObject@Published title 字段,那么WidgetViewModel 可以执行以下操作:

class WidgetViewModel : ObservableObject {
   var widget: Widget

   @Published var title: String = ""
   var cancellable: AnyCancellable?

   init() {
       self.cancellable = widget.$title.receive(on: DispatchQueue.main)
           .sink(receiveValue: self.updateTitle )
   }

   func updateTitle(_: String) {
       self.title = widget.title + "!"
   }
}

Widget 是否也推荐/标准扩展 ObservableObject?如果是这样,WidgetViewModel 如何正确传递更改通知?看起来WidgetModelView.widget 需要同时是@Published 和@ObservedObject,但这似乎不对。

有人对此有任何见解吗?

【问题讨论】:

  • 你不需要widget@Published。您的Widget 可以通过组合发布对title 的更改,如您所展示的,或者您可以使用Notification 或您喜欢的任何其他方法。您不需要Widget 符合ObservableObject 即可拥有title 的发布者。您可以为title 公开Subject
  • 假设我使用了从模型到视图模型的不同通知机制(我将研究这些),有没有办法在没有我设置的 Published 属性的情况下通知视图(即我不'不需要在 ViewModel 中有一个单独的标题字段)?
  • 不,这是同时拥有模型和视图模型的成本。你的视图模型通常有一堆胶水代码来向上/向下传播事件。

标签: ios mvvm swiftui


【解决方案1】:

你的Widget是struct,所以它不能是ObservableObject,你可以这样做

class WidgetViewModel : ObservableObject {

   var widget: Widget {
     didSet {
        updateTitle(widget)    // << here !!
     }
   }

   @Published var title: String = ""

   func updateTitle(_: String) {
       self.title = widget.title + "!"
   }
}

【讨论】:

  • 如果您更新 widget.title,这将无济于事。来自网络请求(我相信这就是问题所在)。
猜你喜欢
  • 2020-05-23
  • 2011-11-03
  • 1970-01-01
  • 2015-04-05
  • 1970-01-01
  • 2013-06-03
  • 1970-01-01
  • 2011-10-02
  • 1970-01-01
相关资源
最近更新 更多