ios - 订阅环境视图模型的子对象内的值更改(发生这种情况时不会重新渲染视图)
问题描述
我有一个视图模型,它是其他子视图模型的父视图。那是:
public class ViewModel: ObservableObject {
@Published var nav = NavigationViewModel()
@Published var screen = ScreenViewModel()
其他子视图模型,例如导航和屏幕,都用于特定目的。例如,nav 的职责是跟踪当前屏幕:
class NavigationViewModel: ObservableObject {
// MARK: Publishers
@Published var currentScreen: Screen = .Timeline
}
ViewModel 在 App 结构中实例化:
@main
struct Appy_WeatherApp: App {
// MARK: Global
var viewModel = ViewModel()
// MARK: -
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(viewModel)
}
}
}
我在任何需要访问它的视图上为它声明一个@EnvironmentObject:
@EnvironmentObject var viewModel: ViewModel
任何引用 ViewModel 的非对象属性的视图,如果@Published
其值发生更改,将导致视图按预期重新呈现。但是,例如,如果 currentScreen@Published
属性发生NavigationViewModel
更改,则视图不会被重新渲染。
我知道如果我从 ViewModel 中分离出来,我可以让它工作NavigationViewModel
,在应用程序级别对其进行实例化,并在访问其任何已发布属性的任何视图中将其用作自己的环境对象。
我的问题是上述解决方法是否实际上是处理此问题的正确方法,和/或是否有任何方法可以让视图订阅环境对象的子对象内的属性值更改?还是有另一种我没有考虑过的方法,这是我试图通过视图模型职责的碎片化来实现的推荐方法?
解决方案
有几种方法可以实现这一点。
选项1
使用Combine
.
import Combine
public class ViewModel: ObservableObject {
@Published var nav = NavigationViewModel()
var anyCancellable: AnyCancellable?
init() {
anyCancellable = nav.objectWillChange.sink { _ in
self.objectWillChange.send()
}
}
}
您基本上只是在navigationViewModel
发布更改时收听。如果是这样,你告诉你的观点,你ViewModel
也有变化。
选项 2
我想由于名称NavigationViewModel
,您会经常在其他视图模型中使用它吗?
如果是这种情况,我会选择单例模式,如下所示:
class NavigationViewModel: ObservableObject {
static let shared = NavigationViewModel()
private init() {}
@Published var currentScreen: Screen = .Timeline
}
在你的内部ViewModel
:
public class ViewModel: ObservableObject {
var nav: NavigationViewModel { NavigationViewModel.shared }
}
您当然也可以在 any 中调用它View
:
struct ContentView: View {
@StateObject var navigationModel = NavigationModel.shared
}
您可能需要objectWillChange.send()
在更改发布者后致电。
@Published var currentScreen: Screen = .Timeline {
didSet {
objectWillChange.send()
}
}
推荐阅读
- apple-m1 - 有没有办法在 bigsur11.3(M1) 上侧载 ios 应用程序?
- javascript - 我可以为 Wemos D1 Mini Lite(ESP8285 芯片)安装 SPIFFS 以使用 JS、HTML 和 CSS 文件作为独立的网络服务器
- download - 尝试下载受保护的 m3u8 视频(我能够下载密钥)
- jquery - laravel中如何使用Event绑定值?
- calculator - 为什么我的程序在一段时间后开始返回错误?
- annotations - 石墨烯:如何在查询执行之前添加一个函数?
- javascript - 如何在 react-Router 的 Link 中传递道具?
- python - 无法打开相机 - OpenCV MacOS Python3
- snowflake-cloud-data-platform - 如何根据雪花中的特定列删除重复项
- c# - C# Datetimepicker 停止验证的方法