XServiceLocator

“渴望拥有合适的依赖注入吗?”

Build Status CocoaPods Compatible Carthage Compatible Platform License: MIT

XServiceLocator 是一个轻量级的 Swift 库/框架,用于动态地为对象提供它们所需的依赖项。该库基于服务定位器模式。其理念是,对象从特定的存储区获取其依赖项。XServiceLocator 使您能够在整个 iOS 应用程序中使用无缝依赖注入,而无需任何后台魔法。

🔩 组件

📦 容器 (Container)

存储关于如何创建已注册类型实例的配置

🛠️ 解析器 (Resolver)

通过使用容器的配置创建类的实例,来解析类型的实际实现

🏭 服务工厂 (ServiceFactory)

用于创建泛型类型实例的通用工厂解决方案

🏃‍♀️ 快速开始

🚶‍♀️ 基本步骤

  1. 使用容器的两种 register 方法中的任何一种注册所有类型。
let container = Container()
            .register(Int.self, instance: 10)
            .register(Double.self) { _ in 20 }
  1. 无论何时需要类型的实例,您都可以使用 Resolver 的两种 resolve 方法中的任何一种来访问它。 首先从 Container 获取 Resolver,然后使用该 Resolver 来解析依赖项。
  let resolver = container.resolver

  let intValue = try! resolver.resolve(Int.self)
  let doubleValue: Double = try! resolver.resolve()

🎲 自定义对象

您还可以为协议注册自定义类型或实例,例如

// Setting up

protocol Shape {
    var name: String { get }
}

class Circle: Shape {
    let name = "Circle"
    let radius: Double

    init(radius: Double) {
        self.radius = radius
    }

}

class Rectangle: Shape {
    let name = "Rectangle"
    let width: Double
    let height: Double

    init(width: Double, height: Double) {
        self.width = width
        self.height = height
    }
}

struct Drawing {
    let shape: Shape
}

// Registering all the dependencies

let container = Container()
    .register(Shape.self, instance: Circle(radius: 10))
    .register(Circle.self) { _ in Circle(radius: 20) }
    .register(Rectangle.self, instance: Rectangle(width: 30, height: 15))
    .register(Drawing.self) { _ in
        let shape = Rectangle(width: 10, height: 5)
        return Drawing(shape: shape)
    }


// Resolving the dependencies

let resolver = container.resolver

let rectangle = try! resolver.resolve(Rectangle.self)
let shape = try! resolver.resolve(Shape.self)
let circle: Circle = try! resolver.resolve()
let drawing: Drawing = try! resolver.resolve()

// Accessing values

print(rectangle.name) // Rectangle
print(shape.name) // Circle
print(circle.name) // Circle
print(drawing.shape.name) // Rectangle

print("\(rectangle.width), \(rectangle.height)") // 30.0, 15.0
print((shape as! Circle).radius) // 10.0
print(circle.radius) // 20.0

🎩 使用已注册的实例进行后续注册

// Registering all the dependencies
let container = Container()
    .register(Double.self, instance: 30)
    .register(Rectangle.self, instance: Rectangle(width: 10, height: 20))
    .register(Circle.self) { resolver in Circle(radius: try! resolver.resolve()) }


// Resolving the dependencies

let resolver = container.resolver

let circle: Circle = try! resolver.resolve()


// Accessing values

circle.radius // 30.0

👶 使用(子)依赖解析器

容器可以将另一个解析器作为依赖项,如果主解析器(容器)无法解析依赖项,则可以使用该解析器进行解析。

// Registering all the dependencies

let dependency = Container()
            .register(Double.self, instance: 100)
            .register(Shape.self, instance: Rectangle(width: 10, height: 20))

let container = Container(dependency: dependency)
    .register(Rectangle.self, instance: Rectangle(width: 15, height: 7.5))


// Resolving the dependencies

let resolver = container.resolver

let shapeRectangle = try! resolver.resolve(Shape.self) as! Rectangle
let rectangle: Rectangle = try! resolver.resolve()
let doubleValue: Double = try! resolver.resolve()


// Accessing values

print("\(shapeRectangle.width), \(shapeRectangle.height)") // 10.0, 20.0
print("\(rectangle.width), \(rectangle.height)") // 15.0, 7.5
print(doubleValue) // 100

💪 解析器数组

解析器数组也充当解析器。 只要数组中的任何元素能够成功解析,就会返回该对象。

// Registering all the dependencies

let container = Container()
    .register(Int.self, instance: 10)
    .register(Double.self, instance: 20)

let container1 = Container()
    .register(Float.self, instance: 30)
    .register(Double.self, instance: 50)

let arrayOfResolvers: Resolver = [
    container,
    container1,
]


// Resolving the dependencies
let intValue = try! arrayOfResolvers.resolve(Int.self)   // 10
let floatValue = try! arrayOfResolvers.resolve(Float.self)   // 30.0
let doubleValue = try! arrayOfResolvers.resolve(Double.self)   // 20.0

🤷‍♂️ 为什么选择 ServiceLocator 模式?

  1. 类/对象之间的松耦合
  2. 提供更好的可测试性
  3. 提供可扩展性。 可以轻松注册新实例,并且可以在不进行大量更改的情况下切换实现。

🤔 为什么选择 XServiceLocator?

  1. 即插即用。 集成该库,即可开始使用。
  2. 支持解析器数组。 可以使用解析器的组合来解析类型。
  3. 支持任何类型的注册和解析。
  4. 由一群真正关心社区及其解决方案质量的开发人员开发和维护。
  5. 一切都仅使用 Swift 构建。 没有 Objective-C 遗留代码。

🛠 安装

CocoaPods

要使用 CocoaPods 将 XServiceLocator 集成到您的 Xcode 项目中,请将以下内容添加到您的 Podfile

pod 'XServiceLocator', '~> 1.0'

Carthage

要使用 Carthage 将 XServiceLocator 集成到您的 Xcode 项目中,请将以下内容添加到您的 Cartfile

github "quickbirdstudios/XServiceLocator" ~> 1.0

然后运行 carthage update

如果这是您第一次在项目中使用 Carthage,您需要执行一些额外的步骤,如Carthage 上所述。

Swift Package Manager

有关如何在您的应用程序中采用 Swift 包的更多信息,请参阅此 WWDC 演示

指定 https://github.com/quickbirdstudios/XServiceLocator.git 作为 XServiceLocator 包链接。

手动

如果您不想使用任何依赖管理工具,您可以手动将 XServiceLocator 集成到您的 iOS 项目中,方法是下载源代码并将文件放在您的项目目录中。

👤 作者

此框架由 QuickBird Studios 用 ❤️ 创建。

❤️ 贡献

如果您需要帮助、发现错误或要讨论功能请求,请打开一个 issue。

如果您想对 XServiceLocator 进行更改,请打开一个 PR。

📃 许可证

XServiceLocator 在 MIT 许可证下发布。 有关更多信息,请参阅 License.md