SwinjectAutoregistration 是 Swinject 的一个扩展,它允许您自动注册您的服务,并大大减少样板代码的数量。
Swinject 可以通过 Carthage、CocoaPods 或 Swift Package Manager 安装。
要使用 Carthage 安装 Swinject,请将以下行添加到您的 Cartfile
。
github "Swinject/Swinject" "2.9.1"
github "Swinject/SwinjectAutoregistration" "2.9.1"
然后运行 carthage update --use-xcframeworks --no-use-binaries
命令或者直接运行 carthage update --use-xcframeworks
。有关 Carthage 的安装和使用的详细信息,请访问 其项目页面。
要使用 CocoaPods 安装 Swinject,请将以下行添加到您的 Podfile
。
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '11.0' # or platform :osx, '10.13' if your target is OS X.
use_frameworks!
pod 'Swinject', '2.9.1'
pod 'SwinjectAutoregistration', '2.9.1'
然后运行 pod install
命令。有关 CocoaPods 的安装和使用的详细信息,请访问 其官方网站。
在 Package.swift
中添加以下内容
dependencies: [
.package(url: "https://github.com/Swinject/SwinjectAutoregistration.git", from: "2.9.1")
],
targets: [
.target(
name: "MyProject",
dependencies: [..., "SwinjectAutoregistration"]
)
...
]
这是一个自动注册宠物主人的简单示例
let container = Container()
container.register(Animal.self) { _ in Cat(name: "Mimi") } // Regular register method
container.autoregister(Person.self, initializer: PetOwner.init) // Autoregistration
其中 PetOwner 看起来像这样
class PetOwner: Person {
let pet: Animal
init(pet: Animal) {
self.pet = pet
}
}
autoregister
函数接收到 PetOwner
的初始化器 init(pet:Animal)
。 从其签名中,Swinject 知道它需要一个依赖项 Animal
并从容器中解析它。 不需要其他任何东西。
当用于注册具有许多依赖项的服务时,自动注册变得特别有用。 比较自动注册代码
container.autoregister(MyService.self, initializer: MyService.init)
与纯 Swinject 中的等效代码
container.register(MyService.self) { r in
MyService(dependencyA: r.resolve(DependencyA.self)!, dependencyB: r.resolve(DependencyB.self)!, dependencyC: r.resolve(DependencyC.self)!, dependencyD: r.resolve(DependencyD.self)!)
}
另一个优点是,如果在开发过程中添加更多依赖项,则无需重写注册代码。
服务也可以被赋予名称 - 与常规注册方法相同。
container.autoregister(Person.self, name: "johnny", initializer: PetOwner.init)
您还可以将自动注册用于具有动态参数的服务。需要将名称作为参数传递的宠物主人定义如下
class PetOwner: Person {
let name: String
let pet: Animal
init(name: String, pet: Animal) {
self.name = name
self.pet = pet
}
}
并像这样注册
container.autoregister(Person.self, argument: String.self, initializer: PetOwner.init)
Swinject 将注册 Person
并传入 String
类型的参数。 当调用 container.resolve(Person.self, argument: "Michael")
时,Swinject 不会尝试将 String
解析为依赖项,而是将 "Michael" 作为名称传递。
要也将宠物作为参数传递,您可以调用
container.autoregister(Person.self, arguments: String.self, Animal.self, initializer: PetOwner.init)
//or
container.autoregister(Person.self, arguments: Animal.self, String.self, initializer: PetOwner.init)
所列参数的顺序可以互换。 自动注册不能与相同类型的更多参数和/或依赖项一起使用。
想知道它是如何工作的吗? 泛型被大量用于自动注册。 对于注册具有两个依赖项的服务,使用类似于以下函数的函数
public func autoregister<Service, A, B>(_ service: Service.Type, initializer: (A, B) -> Service) -> ServiceEntry<Service> {
return self.register(service.self, factory: { r in
return initializer(r.resolve(A.self)!, r.resolve(B.self)!)
} as (ResolverType) -> Service)
}
初始化器是一个像其他任何东西一样的函数。 通过将其作为参数传递,其依赖项可以被推断为 (A, B)
并自动解析。 这些函数是为最多 20 个依赖项生成的。 查看 代码 以获取更多信息。
此扩展还旨在减少样板代码的数量,同时提高注册代码的可读性。 因此,引入了运算符 ~>
。
Petowner(pet: r~>)
// equivalent to
Petowner(pet: r.resolve(Animal.self)!)
依赖关系再次从初始化器中的类型推断。 要指定一个具体的类,您可以使用
Petowner(pet: r ~> Cat.self)
要使用命名服务
Petowner(pet: r ~> (Cat.self, name: "mimi"))
或传递参数
Petowner(pet: r ~> (Cat.self, argument: "Mimi"))
Petowner(pet: r ~> (Cat.self, arguments: ("Mimi", UIColor.black)))
当一个服务有多个初始化器时,swift 编译器不能确定应该使用哪个初始化器,你会得到一个 ambigious use of init(x: y: z:)
。如果该服务正在扩展另一个具有相同数量参数的初始化器的类,也会发生这种情况。
解决方案是像这样指定初始化器
container.autoregister(Person.self, initializer: PetOwner.init(name:pet:))
自动注册不能用于其初始化器中的命名依赖项。 无法从初始化器获取依赖项的名称。 例如,以下代码无法自动注册
container.register(Animal.self, name: "mimi") { _ in Cat(name: "Mimi") }
container.register(Animal.self, name: "charles") { _ in Cat(name: "Charles") }
container.register(Person.self) {
PetOwner(pet: r.resolve(Animal.self, name: "mimi")
}
由于 Swift 5.3 在推断具有默认值的变量的结构中的初始化器时,编译器的行为有所不同
struct Cat {
let height: Int = 50
}
编译器将生成两个 init 函数
Cat.init
和 Cat.init(height:)
由于 Swift 5.3 以下注册
container.autoregister(Animal.self, initializer: Cat.init)
将尝试使用 Cat.init(height:)
,然后会失败,并显示 Unresolved service: Int Initializer: (Int) -> Animal
解决方案是使编译器使用不带参数的 init
container.autoregister(Animal.self, initializer: Cat.init as () -> Cat)
我们的发布程序描述为 Makefile。 运行 make help
命令获取更多信息。
SwinjectAutoregistration 泛型受以下启发
MIT 许可证。 有关详细信息,请参阅 LICENSE 文件。