Swinject 源码框架(三):Object Scopes

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
    }
}

posted on 2019-01-19 21:03  花老🐯  阅读(712)  评论(0编辑  收藏  举报

导航