Object Scopes 指定了生成的实例在系统中是如何被共享的。

如何指定 scope

container.register(Animal.self) { _ in Cat() }
.inObjectScope(.container)

例子如上,每次 register 方法,都会返回 ServiceEntry 实例,然后调用其 inObjectScope 方法,会设置其 objectScope

scope 的种类

  • Transient
    每次调用resolve,都会生成新的实例。
  • Graph (默认值)
    每次手动调用 resolve,都会生成新的实例。
    但是在其 factory 方法中生成的实例,是共享的,即如果已经生成过了,就不会重新生成了。
    用于解决循环依赖
  • Container
    被这个 Container 及其子 Container 共享。可以理解为单例。
  • Weak
    和 Container 类似,但是Container 并不持有它。如果没有其他引用,这个实例会被销毁,下次重新生成。

Scope 的实现

每一个 ServiceEntry 都有持有一个 InstanceStorage,保存着已经生成的 instance
每一次调用 resolve,都会先从其storage中获取 instance。如果获取不到,才会去生成新的实例。

if let persistedInstance = entry.storage.instance(inGraph: currentObjectGraph), let persistedService = persistedInstance as? Service {
return persistedService
} let resolvedInstance = invoker(entry.factory as! Factory)

ServiceEntrystorage 由其objectScope 生成。

internal lazy var storage: InstanceStorage = { [unowned self] in
self.objectScope.makeStorage()
}()

ObjectScopemakeStorage方法,调用了 storageFactory 这个闭包属性。

/// Will invoke and return the result of `storageFactory` closure provided during initialisation.
public func makeStorage() -> InstanceStorage {
if let parent = parent {
return CompositeStorage([storageFactory(), parent.makeStorage()])
} else {
return storageFactory()
}
}

这就意味着每一个ServiceEntrystorage 由其 ObjectScopestorageFactory 属性决定。

Transient 的实现

transientstorageFactoryTransientStorage.init

public static let transient = ObjectScope(storageFactory: TransientStorage.init, description: "transient")

TransientStorage 每次返回的 instance 都是nil,因此每次都生成一个新的实例。

/// Does not persist stored instance.
public final class TransientStorage: InstanceStorage {
public var instance: Any? {
get { return nil }
set {}
} public init() {}
}

Container Scope 的实现

extension InstanceStorage {
public func graphResolutionCompleted() {}
public func instance(inGraph _: GraphIdentifier) -> Any? { return instance }
public func setInstance(_ instance: Any?, inGraph _: GraphIdentifier) { self.instance = instance }
} /// Persists stored instance until it is explicitly discarded.
public final class PermanentStorage: InstanceStorage {
public var instance: Any? public init() {}
}

可见,每次生成一个实例,就会设置为其 instance 属性,并且强持有。
所以只要生成过一次,就不会被释放,也不会重新生成。

Weak Scope 的实现

/// Does not persist value types.
/// Persists reference types as long as there are strong references to given instance.
public final class WeakStorage: InstanceStorage {
private var _instance = Weak<Any>() public var instance: Any? {
get { return _instance.value }
set { _instance.value = newValue }
} public init () {}
}

和 Container 类似,但是这里的instance被包了一层,即一个强对象中,有一个 weak 的属性。真正设置的是其 weak 的属性。
所以这个 storage 并不强持有 instance。因此外部的引用都消失后,instance 的 get 方法会返回 nil。

private class Weak<Wrapped> {
private weak var object: AnyObject?
var value: Wrapped? {
get {
guard let object = object else { return nil }
return object as? Wrapped
}
set { object = newValue as AnyObject? }
}
}

Graph Scope 的实现

/// Persists storage during the resolution of the object graph
public final class GraphStorage: InstanceStorage {
private var instances = [GraphIdentifier: Weak<Any>]()
public var instance: Any? public init() {} public func graphResolutionCompleted() {
instance = nil
} public func instance(inGraph graph: GraphIdentifier) -> Any? {
return instances[graph]?.value
} public func setInstance(_ instance: Any?, inGraph graph: GraphIdentifier) {
self.instance = instance if instances[graph] == nil { instances[graph] = Weak<Any>() }
instances[graph]?.value = instance
}
}

Transient 类似,不过在某一次 resolve 之后,会调用 graphResolutionCompleted,把 instance 清空。

// in Container.swift
fileprivate func decrementResolutionDepth() {
assert(resolutionDepth > 0, "The depth cannot be negative.") resolutionDepth -= 1
if resolutionDepth == 0 {
services.values.forEach { $0.storage.graphResolutionCompleted() }
self.currentObjectGraph = nil
}
}

最新文章

  1. WinForm三级联动
  2. HDU 2896 病毒侵袭
  3. poj2269 Friends
  4. Python实现nb(朴素贝叶斯)
  5. js为数字添加千位分隔符
  6. Linux yum安装和源码安装
  7. linux shell 和linux 命令的区别?windows shell 和 windows 命令呢?
  8. 使用CXF做简单的WebService例子
  9. cmd命令重定向到剪切板
  10. Linux 系统状态检测命令
  11. docker构建tomcat镜像
  12. jQuery(&quot;dom&quot;).get()的源码分析
  13. Java项目导出为jar包+导出第三方jar包+使用命令行调用+传参
  14. Linux下安装Python3和django并配置mysql作为django默认服务器
  15. 【译】第七篇 Integration Services:中级工作流管理
  16. CSS之Flex 布局
  17. 在几份docx文档中里查找某个值
  18. jquery点击事件后增加克隆的标签,并改变克隆的属性加入
  19. QQ兴趣部落 大批量引流实战技巧
  20. 30分钟 带你浅入requirejs源码

热门文章

  1. 新电脑的操作系统win10的所有设置问题汇总
  2. PythonWEB框架之Flask--3
  3. MySQL之练习题5
  4. 541. Reverse String II
  5. 2018.10.04 NOIP模拟 K进制(模拟)
  6. 2018.07.01 BZOJ3295: [Cqoi2011]动态逆序对(带修主席树)
  7. 2018.08.21 NOIP模拟 xorand(01trie)
  8. 一致性哈希Java源码分析
  9. pathinfo()在php不同版本中对于对多字节字符处理的不同结果
  10. PriorityQueue源码分析