如何在 SwiftUI 中通过 ViewModel 传播模型更改?
Posted
技术标签:
【中文标题】如何在 SwiftUI 中通过 ViewModel 传播模型更改?【英文标题】:How to propagate Model changes through ViewModel in SwiftUI? 【发布时间】: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 中有一个单独的标题字段)?
不,这是同时拥有模型和视图模型的成本。你的视图模型通常有一堆胶水代码来向上/向下传播事件。
【参考方案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
,这将无济于事。来自网络请求(我相信这就是问题所在)。以上是关于如何在 SwiftUI 中通过 ViewModel 传播模型更改?的主要内容,如果未能解决你的问题,请参考以下文章
在 SwiftUI 中通过摇动手势(使用 UIKit)设置 EnvironmentObject 不会更新视图
在 SwiftUI 中通过 Date() 读取星期几以获取本地通知
使用 SwiftUI/Combine,如何避免在 ViewModel 中放置可取消项