SwiftUI + MVVM + DI
Posted
技术标签:
【中文标题】SwiftUI + MVVM + DI【英文标题】: 【发布时间】:2021-12-30 12:25:16 【问题描述】:我花了一段时间对此进行研究,发现了很多 SwiftUI、MVVM 和 DI 的示例,但没有一个组合在一起,所以我假设我误解了一些东西。
我有一个新的 SwiftUI 应用程序并打算使用上述内容。
我有以下
一个依赖容器
protocol ViewControllerFactory
func makeFirstViewController() -> First_ViewModel
func makeSecondViewController() -> Second_ViewModel
class DependencyContainer : ObservableObject
let database = AppDatabase()
extension DependencyContainer: ViewControllerFactory
func makeFirstViewController() -> First_ViewModel
return First_ViewModel(appDatabase: database)
func makeSecondViewController() -> Second_ViewModel
return Second_ViewModel()
在我的应用入口点我有:
@main
struct MyApp: App
var body: some Scene
let container = DependencyContainer()
WindowGroup
First_View()
.environment(\.container, container)
private struct Container: EnvironmentKey
static let defaultValue = DependencyContainer()
extension EnvironmentValues
var container: DependencyContainer
get self[Container.self]
set self[Container.self] = newValue
现在我遇到了问题 如何在视图中使用容器?
struct First_View: View
@Environment(\.container) var container
@ObservedObject private var firstViewModel : First_ViewModel
init()
_firstViewModel = container.makeFirstViewController()
报错
“无法将类型 'First_ViewModel' 的值分配给类型 'ObservedObject
如果我像下面这样注入容器,
struct First_View: View
@ObservedObject private var firstViewModel : First_ViewModel
init (container : DependencyContainer)
_firstViewModel = container.makeFirstViewController()
它可以工作,但不是我认为它应该工作的方式
【问题讨论】:
【参考方案1】:@Environment()
属性包装器类型依赖于一组已定义的键名。您可以创建自己的 (this blog post from Use Your Loaf is a good description of how to do this)。不过,这是为值类型设计的。
但是,由于您已经将 DependencyContainer
声明为 ObservableObject
,您可以使用 @EnvironmentObject
属性包装器:
struct MyApp: App
@StateObject var container = DependencyContainer()
var body: some View
WindowGroup
First_View()
.environmentObject(container)
然后,在您需要访问的任何子视图中,您在声明中使用 @EnvironmentObject
包装器。请注意,您必须包含类类型;您可以定义多个环境对象,但每个类最多定义一个。
struct First_View: View
@EnvironmentObject var container: DependencyContainer
// ...
还要注意@EnvironmentObject
假设它能够找到DependencyContainer
的实例 - 如果找不到,它将崩溃。当您在应用程序级别定义一个不应该成为问题的应用程序时。但是,在您的 SwiftUI 预览中,您需要指定一个合适的实例,否则预览子系统可能会崩溃。
因此,如果您有一个静态方法来准备适合预览版的依赖项,您可以编写:
struct First_View_Previews: PreviewProvider
static var previews: some View
First_View()
.environmentObject(DependencyContainer.previewInstance)
【讨论】:
以上是关于SwiftUI + MVVM + DI的主要内容,如果未能解决你的问题,请参考以下文章