使用 Swinject 将 ViewModel 条件注入 ViewController

Posted

技术标签:

【中文标题】使用 Swinject 将 ViewModel 条件注入 ViewController【英文标题】:Conditional injection of ViewModel into ViewController using Swinject 【发布时间】:2017-03-22 12:10:33 【问题描述】:

我正在使用Swinject 注入依赖项,到目前为止它运行良好。但是现在我有一个场景,我有一个ViewController,它依赖于它的ViewModelViewModel 符合 ViewModeling 协议,并且可以是两种类型之一(两者都符合相同的协议,但具有截然不同的行为)。

我试图弄清楚我怎样才能注入正确的ViewModel(必须在运行时做出决定)?

我注意到我可以使用Container 通过name 注册每个ViewModel,然后使用name 来区分应该注入哪个ViewModel,这乍一看似乎不错解决方案 - 直到我发现我无法使用名称实例化 ViewController(或者我可能错过了它?)

我还考虑过在我的 DependencyInjector 类上公开一个属性,该属性将用于手动注入正确的 ViewModel - 尽管我觉得这种方法完全错过了自动依赖注入解决方案的意义,并且还强迫我用一些业务逻辑代码弄脏依赖注入器。

任何帮助或想法将不胜感激。

【问题讨论】:

您是否将 SwinjectStoryboard 用于视图控制器?如果是这样,您可以在情节提要中使用swinjectRegistrationName 属性:github.com/Swinject/SwinjectStoryboard#registration-with-name 我正在使用SwinjectStoryboard,但您的建议意味着我必须保留两个重复的ViewControllers,并且每个都有不同的名称 - 这对我来说似乎是一个问题(每次更改在ViewController 中意味着我必须记住更新两个副本) 【参考方案1】:

不将 DI 与应用程序逻辑混合的一种方法是使用某种“代理”视图模型,该模型将实现用于区分两种变体的逻辑。您可以使用不同的接口来实现它,例如

protocol ViewModelProxy 
    var viewModel: ViewModel  get 

或更透明地:

protocol ViewModel 
    func foo()


class ViewModelProxy: ViewModel 
    private let viewModel1: ViewModel
    private let viewModel2: ViewModel

    private var viewModel: ViewModel 
        if shouldUseViewModel1 
            return viewModel1
         else 
            return viewModel2
        
    

    func foo() 
        viewModel.foo()
    

那么你总是可以将ViewModelProxy 注入到视图控制器中。

【讨论】:

以上是关于使用 Swinject 将 ViewModel 条件注入 ViewController的主要内容,如果未能解决你的问题,请参考以下文章

在初始化之外绑定 ViewModel 事件

如何将正确的 viewModel 注入单个 viewController

Swinject:如何将委托模式与接口隔离(类与接口)一起使用?

Swinject 将 self 的属性注入新的 UIViewController

我在 Swinject 中做错了啥?

Swinject:迁移到程序集