Swinject注册UIViewController最佳实践

Posted

技术标签:

【中文标题】Swinject注册UIViewController最佳实践【英文标题】:Swinject register UIViewController best practice 【发布时间】:2017-03-27 20:26:20 【问题描述】:

在我的项目中,此时我使用 Swinject(DI 容器)。

如果我有以下层次结构,我想知道如何注册 ViewController:

class RateAnswersBaseVC: UIViewController  
class RateAnswersDoctorVC: RateAnswersBaseVC  
class RateAnswersQualityVC: RateAnswersBaseVC  

他们将如何注册和使用?在这个项目中我有两个选项我使用第一个选项,但有一种感觉我们应该使用第二个:)

// ------- 1 --------
container.register(RateAnswersDoctorVC.self)  r in
    let vc: RateAnswersDoctorVC = RateAnswersDoctorVC()
    self.configureBasicFields(with: vc, container: container, resolver: r)
    return vc


container.register(RateAnswersQualityVC.self)  r in
    let vc: RateAnswersQualityVC = RateAnswersQualityVC()
    self.configureBasicFields(with: vc, container: container, resolver: r)
    return vc


// ------- 2 --------
container.register(RateAnswersBaseVC.self, name: "doctor")  r in
    let vc: RateAnswersDoctorVC = RateAnswersDoctorVC()
    self.configureBasicFields(with: vc, container: container, resolver: r)
    return vc


container.register(RateAnswersBaseVC.self, name: "quality")  r in
    let vc: RateAnswersQualityVC = RateAnswersQualityVC()
    self.configureBasicFields(with: vc, container: container, resolver: r)
    return vc

如果您能解释一下为什么要使用其中一种方法,我会很高兴。

感谢回复

【问题讨论】:

【参考方案1】:

嗯,无论是 1 还是 2,您仍在注册实例。 在这种情况下,我真的看不出有什么不同。

这些是 ViewController,所以事情有点复杂,但不同之处在于将它们注册为 RateAnswersBaseVC,而不是将它们注册为协议 RateAnswersBaseVCServiceRateAnswersBaseVCProtocol,这样您就可以创建一个不同的在 mocks 中实现 View Controller 以进行测试。

【讨论】:

【参考方案2】:

上次我在我的项目中使用 MVVM 模式。所以我将应用程序的业务逻辑拆分为 modules - 一个完整的代码部分,提供一些功能或业务逻辑(如在应用程序中登录、全屏播放视频等)。对于每个模块,我创建一个Assembly 对象来配置模块中的依赖项。

class PasswordAssembly: Assembly 
     func assemble(container: Container) 
        container.register(PasswordViewInterface.self)  (_: Resolver) in
            PasswordViewController(nibName: "PasswordViewController", bundle: nil)
        
        .initCompleted  resolver, view in
            var view = view as PasswordViewInterface
            view.viewModel = resolver.resolve(PasswordViewModelInterface.self)
            view.router = resolver.resolve(PasswordRouterInterface.self)
        

        container.register(PasswordViewModelInterface.self)  (resolver: Resolver) in
            return PasswordViewModel(coreModel: resolver.resolve(CoreViewModelInterface.self)!)
        

        container.register(PasswordRouterInterface.self)  _ in
            return PasswordRouter()
        
        .initCompleted  (resolver, router) in
            var router = router as PasswordRouterInterface
            router.view = resolver.resolve(PasswordViewInterface.self)
            router.resolver = container
        
    

我还注入路由器 Resolver (Container) 对象以使 Router 构建层次结构

protocol PasswordRouterInterface 
    var view: PasswordViewInterface!  get set 
    var resolver: Resolver!  get set 

    func presentFilesListView()
    func presentContentView()


class PasswordRouter: PasswordRouterInterface 
    var view: PasswordViewInterface!
    var resolver: Resolver!

    func presentFilesListView() 
        if let listViewController = resolver.resolve(FilesListViewInterface.self)?.getViewController() 
            let navigationController = UINavigationController(rootViewController: listViewController)
            view.getViewController().present(navigationController, animated: true) 

            
        
    

    func presentContentView() 

    

【讨论】:

以上是关于Swinject注册UIViewController最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

Swinject:生成任何对象的实例(对于未注册的对象、ViewModel 等...)

Swinject 返回 nil,因为对象注册错误

使用 swinject 注册具有关联类型的协议时出现问题

Swinject:使用弱范围会泄漏对象

如何使用 swinject 正确注入依赖项

当对象范围为容器时,多次调用 Swinject 工厂关闭