You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

101 lines
3.7 KiB

2 years ago
  1. //
  2. // Copyright © 2019 Swinject Contributors. All rights reserved.
  3. //
  4. import Foundation
  5. // A generic-type-free protocol to be the type of values in a strongly-typed collection.
  6. internal protocol ServiceEntryProtocol: AnyObject {
  7. func describeWithKey(_ serviceKey: ServiceKey) -> String
  8. var objectScope: ObjectScopeProtocol { get }
  9. var storage: InstanceStorage { get }
  10. var factory: FunctionType { get }
  11. var initCompleted: (FunctionType)? { get }
  12. var serviceType: Any.Type { get }
  13. }
  14. /// The `ServiceEntry<Service>` class represents an entry of a registered service type.
  15. /// As a returned instance from a `register` method of a `Container`, some configurations can be added.
  16. public final class ServiceEntry<Service>: ServiceEntryProtocol {
  17. fileprivate var initCompletedActions: [(Resolver, Service) -> Void] = []
  18. internal let serviceType: Any.Type
  19. internal let argumentsType: Any.Type
  20. internal let factory: FunctionType
  21. internal weak var container: Container?
  22. internal var objectScope: ObjectScopeProtocol = ObjectScope.graph
  23. internal lazy var storage: InstanceStorage = { [unowned self] in
  24. self.objectScope.makeStorage()
  25. }()
  26. internal var initCompleted: FunctionType? {
  27. guard !initCompletedActions.isEmpty else { return nil }
  28. return { [weak self] (resolver: Resolver, service: Any) -> Void in
  29. guard let strongSelf = self else { return }
  30. strongSelf.initCompletedActions.forEach { $0(resolver, service as! Service) }
  31. }
  32. }
  33. internal init(serviceType: Service.Type, argumentsType: Any.Type, factory: FunctionType) {
  34. self.serviceType = serviceType
  35. self.argumentsType = argumentsType
  36. self.factory = factory
  37. }
  38. internal convenience init(
  39. serviceType: Service.Type,
  40. argumentsType: Any.Type,
  41. factory: FunctionType,
  42. objectScope: ObjectScope
  43. ) {
  44. self.init(serviceType: serviceType, argumentsType: argumentsType, factory: factory)
  45. self.objectScope = objectScope
  46. }
  47. /// Specifies the object scope to resolve the service.
  48. ///
  49. /// - Parameter scope: The `ObjectScopeProtocol` value.
  50. ///
  51. /// - Returns: `self` to add another configuration fluently.
  52. @discardableResult
  53. public func inObjectScope(_ objectScope: ObjectScopeProtocol) -> Self {
  54. self.objectScope = objectScope
  55. return self
  56. }
  57. /// Specifies the object scope to resolve the service.
  58. /// Performs the same functionality as `inObjectScope(_: ObjectScopeProtocol) -> Self`,
  59. /// but provides more convenient usage syntax.
  60. ///
  61. /// - Parameter scope: The `ObjectScope` value.
  62. ///
  63. /// - Returns: `self` to add another configuration fluently.
  64. @discardableResult
  65. public func inObjectScope(_ objectScope: ObjectScope) -> Self {
  66. return inObjectScope(objectScope as ObjectScopeProtocol)
  67. }
  68. /// Adds the callback to setup the instance after its `init` completes.
  69. /// *Property or method injections* can be performed in the callback.
  70. /// To resolve *circular dependencies*, `initCompleted` must be used.
  71. ///
  72. /// - Parameter completed: The closure to be called after the instantiation of the registered service.
  73. ///
  74. /// - Returns: `self` to add another configuration fluently.
  75. @discardableResult
  76. public func initCompleted(_ completed: @escaping (Resolver, Service) -> Void) -> Self {
  77. initCompletedActions.append(completed)
  78. return self
  79. }
  80. internal func describeWithKey(_ serviceKey: ServiceKey) -> String {
  81. return description(
  82. serviceType: serviceType,
  83. serviceKey: serviceKey,
  84. objectScope: objectScope,
  85. initCompleted: initCompletedActions
  86. )
  87. }
  88. }