
正文
Swinject 源码框架(一):基本原理
提示:扫一扫查出行【扫一扫了解最新限行尾号】
复制提示

核心是
Container
类。它提供了两类方法,
register
和
resolve
。
为了找到在
resolve
时,能够找到对应的方法,内部维护了一个叫做
services
的字典。key 是根据
serviceType
、
name
、
argumentsType
确定的。
在
register
时,会字典里加入一个条目。在
resolve
时,会根据字典,找到对应的
ServiceEntryProtocol
,然后调用其方法生成一个 component。
Container 类
register
方法
public func _register<Service, Arguments>(
_ serviceType: Service.Type,
factory: @escaping (Arguments) -> Any,
name: String? = nil,
option: ServiceKeyOption? = nil
) -> ServiceEntry<Service> {
let key = ServiceKey(serviceType: Service.self, argumentsType: Arguments.self, name: name, option: option)
let entry = ServiceEntry(
serviceType: serviceType,
argumentsType: Arguments.self,
factory: factory,
objectScope: defaultObjectScope
)
entry.container = self
services[key] = entry
behaviors.forEach { $0.container(self, didRegisterType: serviceType, toService: entry, withName: name) }
return entry
}
register
方法
public func _register<Service, Arguments>(
_ serviceType: Service.Type,
factory: @escaping (Arguments) -> Any,
name: String? = nil,
option: ServiceKeyOption? = nil
) -> ServiceEntry<Service> {
let key = ServiceKey(serviceType: Service.self, argumentsType: Arguments.self, name: name, option: option)
let entry = ServiceEntry(
serviceType: serviceType,
argumentsType: Arguments.self,
factory: factory,
objectScope: defaultObjectScope
)
entry.container = self
services[key] = entry
behaviors.forEach { $0.container(self, didRegisterType: serviceType, toService: entry, withName: name) }
return entry
}
如上所示,先生成了一个
ServiceKey
,然后生成了一个
ServiceEntry
,再把这两个值在字典里对应。
resolve
方法
var resolvedInstance: Service?
let key = ServiceKey(serviceType: Service.self, argumentsType: Arguments.self, name: name, option: option)
if let entry = getEntry(for: key) {
resolvedInstance = resolve(entry: entry, invoker: invoker)
}
if resolvedInstance == nil {
resolvedInstance = resolveAsWrapper(name: name, option: option, invoker: invoker)
}
即先生成一个
ServiceKey
,然后根据这个 key 找到一个
ServiceEntry
,然后根据这个 entry 和传入的方法,生成一个实例,返回。
ServiceKey
ServiceKey
是一个结构体,用来标识注册的一个服务。
// MARK: - ServiceKey
internal struct ServiceKey {
internal let serviceType: Any.Type
internal let argumentsType: Any.Type
internal let name: String?
}
// MARK: Hashable
extension ServiceKey: Hashable {
var hashValue: Int {
return ObjectIdentifier(serviceType).hashValue
^ ObjectIdentifier(argumentsType).hashValue
^ (name?.hashValue ?? 0)
}
}
由于
ServiceKey
把
name
、
serviceType
、
argumentsType
都考虑在内了,所以下面两个注册,对应的是不同的
ServiceKey
。 因为参数的类型不一样。
第一个参数类型是(String, Bool),第二个参数类型是 (Bool, String)。
container.register(Animal.self) { _, name, running in
Horse(name: name, running: running)
}
container.register(Animal.self) { _, running, name in
Horse(name: name, running: running)
}
ServiceEntry
ServiceEntry
实现了
ServiceEntryProtocol
方法,用来保存对应
ServiceKey
生产的实例,以及控制对象的范围(Object Scopes)。
在初始化时,会把
serviceType
、
argumentsType
、component 的构造方法
factory
作为参数传递。
在
resolve
时,
如有必要
会取出
ServiceEntry
的
factory
,然后结合传过来的参数,调用
factory
生成一个 component(即实例)
let resolvedInstance = invoker(entry.factory as! Factory)






