Swift 中的依赖注入

Posted

技术标签:

【中文标题】Swift 中的依赖注入【英文标题】:Dependency Injection in Swift 【发布时间】:2018-09-26 14:40:58 【问题描述】:

我完全爱上了依赖注入。我喜欢它让你有可能遵循 SOLID 原则的方式,以及它防止意大利面条代码的方式。我在我的一个 android 项目中使用了 Dagger,一切都更加干净、模块化和可测试。 现在我正在做一个 Swift 项目。我想在不使用任何第三方库的情况下遵循这种设计模式(由于缺乏当前的代码库和项目承诺)。所以,我决定创建一个自制的实现。

import UIKit

class DependencyContainer 
    private var dependencies = [String: AnyObject]()

    struct Static 
        static var instance: DependencyContainer?
    

    static var shared: DependencyContainer 
        if Static.instance == nil 
            Static.instance = DependencyContainer()
        

        return Static.instance!
    

    init() 
        AppDelegate.print("Dependency container instantiated")
    

    func resolve(_ classIdentifier: String) -> AnyObject 
        if dependencies[classIdentifier] == nil 
            dependencies[classIdentifier] = getClassInstance(classIdentifier)
        

        return dependencies[classIdentifier]!
    

    private func getClassInstance(_ classIdentifier: String) -> AnyObject 
        var instance: AnyObject! = nil
        let classInstance = NSClassFromString(classIdentifier) as! NSObject.Type
        instance = classInstance.init()

        return instance
    

    func dispose() 
        DependencyContainer.Static.instance = nil
    

在我需要注入依赖项的地方,我按如下方式进行:

dataRepository = DependencyContainer.shared.resolve(NSStringFromClass(DataRepositoryImplementation)) as! DataRepository

目前一切正常,但我认为这种方法存在很多限制。你有什么建议吗?

【问题讨论】:

您的代码中的 Service LocatorDependency Injection 更多。如果您想了解 Martin Fowler 的 article 的优缺点,必读!!跨度> Dependency injection means giving an object its instance variables. Really. That's it。 DI 不需要容器或单例。 这是另一篇关于 DI 的好文章:swiftbysundell.com/posts/… 我真的要感谢你们的回答。我刚读了你的建议。我想要实现的是找到一种方法来正确注入依赖项(构造函数、属性或参数)。在这一点上,您认为我唯一的方法是使用 Typhoon 或 Swinject? @JJack_ 您可能还想检查 weaver (github.com/scribd/Weaver)。它允许您通过注释在类中声明依赖项。基于此,它会自动为您生成依赖注入容器并执行一些预编译检查以确保您的依赖图是正确的。 【参考方案1】:

是的,通过您的方法,您需要将所有应用程序对象注册到一个容器中。此外,您没有使用泛型来推断您正在解析的类型并使您的容器类型安全。

你可以使用https://github.com/JulianAlonso/Injection,它类型安全,有粒度,而且它是一个非常轻量级的库。

【讨论】:

【参考方案2】:

我知道一个超轻的依赖注入容器。 DIContainer

这很好,因为您可以在属性之前使用@Injected 解决依赖关系,或者如果您愿意,可以调用方法resolve

例如:

@Injected(.githubService)
var githubService: FetchService

@Injected(.by(type: FetchService.self, withKey: "gitlab"))
var gitlabService: FetchService

@InjectedSafe
var externalService: ExternalSingletonService?

let githubService = try? Container.standard.resolve(.githubService)
let gitlabService = try? Container.standard.resolve(.by(type: FetchService.self, withKey: "gitlab"))
let externalService = try? Container.standard.resolve(.by(type: ExternalSingletonService.self))

希望对你的成就有所帮助。

【讨论】:

以上是关于Swift 中的依赖注入的主要内容,如果未能解决你的问题,请参考以下文章

在swift中,当应用程序进入后台时,如何使用依赖注入保存变量?

译 Node.js 中的依赖注入

一文搞懂│php 中的 DI 依赖注入

一文搞懂│php 中的 DI 依赖注入

一文搞懂│php 中的 DI 依赖注入

译 Node.js 中的依赖注入