// // Copyright © 2019 Swinject Contributors. All rights reserved. // import Foundation // A generic-type-free protocol to be the type of values in a strongly-typed collection. internal protocol ServiceEntryProtocol: AnyObject { func describeWithKey(_ serviceKey: ServiceKey) -> String var objectScope: ObjectScopeProtocol { get } var storage: InstanceStorage { get } var factory: FunctionType { get } var initCompleted: (FunctionType)? { get } var serviceType: Any.Type { get } } /// The `ServiceEntry` class represents an entry of a registered service type. /// As a returned instance from a `register` method of a `Container`, some configurations can be added. public final class ServiceEntry: ServiceEntryProtocol { fileprivate var initCompletedActions: [(Resolver, Service) -> Void] = [] internal let serviceType: Any.Type internal let argumentsType: Any.Type internal let factory: FunctionType internal weak var container: Container? internal var objectScope: ObjectScopeProtocol = ObjectScope.graph internal lazy var storage: InstanceStorage = { [unowned self] in self.objectScope.makeStorage() }() internal var initCompleted: FunctionType? { guard !initCompletedActions.isEmpty else { return nil } return { [weak self] (resolver: Resolver, service: Any) -> Void in guard let strongSelf = self else { return } strongSelf.initCompletedActions.forEach { $0(resolver, service as! Service) } } } internal init(serviceType: Service.Type, argumentsType: Any.Type, factory: FunctionType) { self.serviceType = serviceType self.argumentsType = argumentsType self.factory = factory } internal convenience init( serviceType: Service.Type, argumentsType: Any.Type, factory: FunctionType, objectScope: ObjectScope ) { self.init(serviceType: serviceType, argumentsType: argumentsType, factory: factory) self.objectScope = objectScope } /// Specifies the object scope to resolve the service. /// /// - Parameter scope: The `ObjectScopeProtocol` value. /// /// - Returns: `self` to add another configuration fluently. @discardableResult public func inObjectScope(_ objectScope: ObjectScopeProtocol) -> Self { self.objectScope = objectScope return self } /// Specifies the object scope to resolve the service. /// Performs the same functionality as `inObjectScope(_: ObjectScopeProtocol) -> Self`, /// but provides more convenient usage syntax. /// /// - Parameter scope: The `ObjectScope` value. /// /// - Returns: `self` to add another configuration fluently. @discardableResult public func inObjectScope(_ objectScope: ObjectScope) -> Self { return inObjectScope(objectScope as ObjectScopeProtocol) } /// Adds the callback to setup the instance after its `init` completes. /// *Property or method injections* can be performed in the callback. /// To resolve *circular dependencies*, `initCompleted` must be used. /// /// - Parameter completed: The closure to be called after the instantiation of the registered service. /// /// - Returns: `self` to add another configuration fluently. @discardableResult public func initCompleted(_ completed: @escaping (Resolver, Service) -> Void) -> Self { initCompletedActions.append(completed) return self } internal func describeWithKey(_ serviceKey: ServiceKey) -> String { return description( serviceType: serviceType, serviceKey: serviceKey, objectScope: objectScope, initCompleted: initCompletedActions ) } }