diff --git a/.Package.Test.swift b/.Package.Test.swift deleted file mode 100644 index 604e53cb..00000000 --- a/.Package.Test.swift +++ /dev/null @@ -1,27 +0,0 @@ -// swift-tools-version:5.0 - -import PackageDescription - -let package = Package( - name: "Swinject", - products: [ - .library( - name: "Swinject", - targets: ["Swinject"] - ), - ], - dependencies: [], - targets: [ - .target( - name: "Swinject", - dependencies: [], - path: "Sources" - ), - .testTarget( - name: "SwinjectTests", - dependencies: [ - "Swinject", - ] - ), - ] -) diff --git a/.github/workflows/Pod Lint.yml b/.github/workflows/Pod Lint.yml index 1bbd3b99..227fba54 100644 --- a/.github/workflows/Pod Lint.yml +++ b/.github/workflows/Pod Lint.yml @@ -2,16 +2,22 @@ name: Pod Lint on: - workflow_dispatch: -env: - ENCODING: LC_CTYPE=en_US.UTF-8 - DEVELOPER_DIR: /Applications/Xcode_12.4.app/Contents/Developer + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] jobs: pod-lint: - runs-on: macos-10.15 + runs-on: macos-15 + env: + ENCODING: LC_CTYPE=en_US.UTF-8 + DEVELOPER_DIR: /Applications/Xcode_16.4.app/Contents/Developer steps: - name: Checkout repository - uses: actions/checkout@v2 - - name: Linting PodSpec for Cocoapods" - run: export "${{ env. ENCODING }}" | pod lib lint - shell: bash \ No newline at end of file + uses: actions/checkout@v4 + - name: Inspect Environment + run: xcrun simctl list + shell: bash + - name: Linting PodSpec for Cocoapods + run: export "${{ env. ENCODING }}" | pod lib lint --verbose + shell: bash diff --git a/.github/workflows/Project Testing.yml b/.github/workflows/Project Testing.yml index acf981c8..09f89bc4 100644 --- a/.github/workflows/Project Testing.yml +++ b/.github/workflows/Project Testing.yml @@ -5,33 +5,33 @@ on: workflow_dispatch: env: PROJECT: Swinject.xcodeproj - DEVELOPER_DIR: /Applications/Xcode_12.4.app/Contents/Developer + DEVELOPER_DIR: /Applications/Xcode_16.4.app/Contents/Developer jobs: test: - runs-on: macos-10.15 + runs-on: macos-15 strategy: matrix: include: - platform-version: iOS - DEST: "OS=14.4,name=iPhone 8" + DEST: "OS=18.4,name=iPhone 16" SCHEME: "Swinject-iOS" SDK: "iphonesimulator" ACTION: "test" PLATFORM: "iOS" - platform-version: macOS - DEST: "arch=x86_64" + DEST: "arch=arm64" SCHEME: "Swinject-macOS" SDK: "macosx" ACTION: "test" PLATFORM: "OSX" - platform-version: tvOS - DEST: "OS=14.3,name=Apple TV 4K" + DEST: "OS=18.4,name=Apple TV 4K" SCHEME: "Swinject-tvOS" SDK: "appletvsimulator" ACTION: "test" PLATFORM: "tvOS" - platform-version: watchOS - DEST: "OS=7.2,name=Apple Watch Series 6 - 44mm" + DEST: "OS=11.4,name=Apple Watch Series 10 - 46mm" SCHEME: "Swinject-watchOS" SDK: "watchsimulator" ACTION: "build" diff --git a/.github/workflows/SPM Testing.yml b/.github/workflows/SPM Testing.yml index f3366c11..e8cf4ac3 100644 --- a/.github/workflows/SPM Testing.yml +++ b/.github/workflows/SPM Testing.yml @@ -1,17 +1,23 @@ # This is the First Workflow for Testing with Github Actions name: SPM Check + on: - workflow_dispatch: -env: - DEVELOPER_DIR: /Applications/Xcode_12.4.app/Contents/Developer + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + jobs: spm-check: - runs-on: macos-10.15 + env: + DEVELOPER_DIR: /Applications/Xcode_16.4.app/Contents/Developer + runs-on: macos-15 steps: - - uses: actions/checkout@v2 - - name: Setup Package File - run: mv .Package.Test.swift Package.swift + - uses: actions/checkout@v4 + - uses: swift-actions/setup-swift@v2 + with: + swift-version: "6.0.3" - name: Build run: swift build -v - name: Run tests diff --git a/.swiftformat b/.swiftformat index 764587c3..590eae76 100644 --- a/.swiftformat +++ b/.swiftformat @@ -1,4 +1,4 @@ ---swiftversion 5.0 +--swiftversion 6.0 --exclude .Package.Test.swift --exclude Package.swift --header "\n Copyright © {created.year} Swinject Contributors. All rights reserved.\n" diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 1a3e6f73..00000000 --- a/.travis.yml +++ /dev/null @@ -1,54 +0,0 @@ -language: objective-c -env: - global: - - LC_CTYPE=en_US.UTF-8 - - PROJECT=Swinject.xcodeproj -git: - submodules: false -addons: - homebrew: - packages: - - xcodegen -matrix: - include: - - env: JOB="LINUX_SPM" SWIFT_VERSION="5.2.2" - os: linux - language: generic - sudo: required - dist: bionic - before_install: - - eval "$(curl -sL https://swiftenv.fuller.li/install.sh)" - before_script: - script: - - mv .Package.Test.swift Package.swift - - swift build - - swift test - - env: JOB="POD_LINT" - osx_image: xcode12.5 - before_install: - script: - - pod lib lint - - env: JOB="XCODE" DEST="OS=14.0.1,name=iPhone 8" SCHEME="Swinject-iOS" SDK="iphonesimulator" ACTION="test" PLATFORM="iOS" - osx_image: xcode12.5 - - env: JOB="XCODE" DEST="arch=x86_64" SCHEME="Swinject-macOS" SDK="macosx" ACTION="test" PLATFORM="OSX" - osx_image: xcode12.5 - - env: JOB="XCODE" DEST="OS=14.0,name=Apple TV 4K" SCHEME="Swinject-tvOS" SDK="appletvsimulator" ACTION="test" PLATFORM="tvOS" - osx_image: xcode12.5 - - env: JOB="XCODE" DEST="OS=7.0,name=Apple Watch Series 6 - 44mm" SCHEME="Swinject-watchOS" SDK="watchsimulator" ACTION="build" PLATFORM="watchOS" - osx_image: xcode12.5 - -before_install: - - xcconfig=$(mktemp /tmp/static.xcconfig.XXXXXX) - - trap 'rm -f "$xcconfig"' INT TERM HUP EXIT - - echo 'EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1200 = arm64 arm64e armv7 armv7s armv6 armv8' >> $xcconfig - - echo 'EXCLUDED_ARCHS = $(inherited) $(EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_$(EFFECTIVE_PLATFORM_SUFFIX)__NATIVE_ARCH_64_BIT_$(NATIVE_ARCH_64_BIT)__XCODE_$(XCODE_VERSION_MAJOR))' >> $xcconfig - - export XCODE_XCCONFIG_FILE="$xcconfig" -before_script: - - rm -r Swinject.xcodeproj - - xcodegen generate -script: - - set -o pipefail - - xcodebuild "$ACTION" -project "$PROJECT" -scheme "$SCHEME" -sdk "$SDK" -destination "$DEST" -configuration Release ENABLE_TESTABILITY=YES | xcpretty -notifications: - email: - on_success: never diff --git a/Package.swift b/Package.swift index 4387e099..abc6084e 100644 --- a/Package.swift +++ b/Package.swift @@ -1,21 +1,19 @@ -// swift-tools-version:5.0 +// swift-tools-version:6.0.0 import PackageDescription let package = Package( name: "Swinject", platforms: [ - .macOS(.v10_10), - .iOS(.v9), - .tvOS(.v9), - .watchOS(.v2) + .macOS(.v10_13), + .iOS(.v12), + .tvOS(.v12), + .watchOS(.v4), + .visionOS(.v1) ], products: [ .library(name: "Swinject", targets: ["Swinject"]), - .library(name: "Swinject-Dynamic", - type: .dynamic, - targets: ["Swinject"]), ], targets: [ .target(name: "Swinject", diff --git a/README.md b/README.md index c0c9e2b3..3d1b84c2 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,6 @@ Swinject ======== -[![Travis CI Com](https://travis-ci.com/Swinject/Swinject.svg?branch=master)](https://travis-ci.com/Swinject/Swinject) ![Github Actions](https://github.com/1ucas/Swinject/actions/workflows/Project%20Testing.yml/badge.svg?branch=master) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![CocoaPods Version](https://img.shields.io/cocoapods/v/Swinject.svg?style=flat)](http://cocoapods.org/pods/Swinject) @@ -18,6 +17,8 @@ Swinject is a lightweight [dependency injection](https://en.wikipedia.org/wiki/D Dependency injection (DI) is a software design pattern that implements Inversion of Control (IoC) for resolving dependencies. In the pattern, Swinject helps your app split into loosely-coupled components, which can be developed, tested and maintained more easily. Swinject is powered by the Swift generic type system and first class functions to define dependencies of your app simply and fluently. +Swinject is maintained by the [Faire Wholesale Inc.](https://github.com/Faire?view_as=public) mobile platform team. + ## Features - [x] [Pure Swift Type Support](./Documentation/README.md#user-content-pure-swift-type-support) @@ -280,7 +281,7 @@ The DI container features of Swinject are inspired by: and highly inspired by: -- [Funq](http://funq.codeplex.com) - [Daniel Cazzulino](http://www.codeplex.com/site/users/view/dcazzulino) and [the project team](http://funq.codeplex.com/team/view). +- [Funq](https://github.com/kzu/funq) - [Daniel Cazzulino](https://github.com/kzu). ## License diff --git a/Sources/Behavior.swift b/Sources/Behavior.swift index 8f5db054..843bab8d 100644 --- a/Sources/Behavior.swift +++ b/Sources/Behavior.swift @@ -5,7 +5,7 @@ /// Protocol for adding functionality to the container public protocol Behavior { /// This will be invoked on each behavior added to the `container` for each `entry` added to the container using - /// one of the `register()` or type forwading methods + /// one of the `register()` or type forwarding methods /// /// - Parameters: /// - container: container into which an `entry` has been registered @@ -13,7 +13,8 @@ public protocol Behavior { /// - entry: ServiceEntry registered to the `container` /// - name: name under which the service has been registered to the `container` /// - /// - Remark: `Type` and `Service` can be different types in the case of type forwarding + /// - Remark: `Type` and `Service` can be different types in the case of type forwarding (commonly used as `.implements()`). + /// `Type` will represent the forwarded type key, and `Service` will represent the destination. func container( _ container: Container, didRegisterType type: Type.Type, diff --git a/Sources/Container.Arguments.erb b/Sources/Container.Arguments.erb index 4d32c739..74bc0bdb 100644 --- a/Sources/Container.Arguments.erb +++ b/Sources/Container.Arguments.erb @@ -18,7 +18,7 @@ import Foundation -// MARK: - Registeration with Arguments +// MARK: - Registration with Arguments extension Container { <% (1..arg_count).each do |i| %> <% arg_types = (1..i).map { |n| "Arg#{n}" }.join(", ") %> diff --git a/Sources/Container.Arguments.swift b/Sources/Container.Arguments.swift index c62e853a..6c5554f8 100644 --- a/Sources/Container.Arguments.swift +++ b/Sources/Container.Arguments.swift @@ -12,7 +12,7 @@ import Foundation -// MARK: - Registeration with Arguments +// MARK: - Registration with Arguments extension Container { /// Adds a registration for the specified service with the factory closure to specify how the service is resolved with dependencies. diff --git a/Sources/Container.Logging.swift b/Sources/Container.Logging.swift index 1ae32b29..e4c163cd 100644 --- a/Sources/Container.Logging.swift +++ b/Sources/Container.Logging.swift @@ -2,19 +2,11 @@ // Copyright © 2019 Swinject Contributors. All rights reserved. // -public typealias LoggingFunctionType = (String) -> Void - +import Foundation public extension Container { - /// Function to be used for logging debugging data. - /// Default implementation writes to standard output. - static var loggingFunction: LoggingFunctionType? { - get { return _loggingFunction } - set { _loggingFunction = newValue } - } - internal static func log(_ message: String) { - _loggingFunction?(message) + if ProcessInfo.processInfo.environment["SWINJECT_LOGGING_ENABLED"] == "1" { + print(message) + } } } - -private var _loggingFunction: LoggingFunctionType? = { print($0) } diff --git a/Sources/Container.TypeForwarding.swift b/Sources/Container.TypeForwarding.swift index 14813891..46f9c042 100644 --- a/Sources/Container.TypeForwarding.swift +++ b/Sources/Container.TypeForwarding.swift @@ -25,7 +25,9 @@ extension Container { name: name, option: nil ) - services[key] = service - behaviors.forEach { $0.container(self, didRegisterType: type, toService: service, withName: name) } + syncIfEnabled { + services[key] = service + behaviors.forEach { $0.container(self, didRegisterType: type, toService: service, withName: name) } + } } } diff --git a/Sources/Container.swift b/Sources/Container.swift index 44ec0186..f6e44430 100644 --- a/Sources/Container.swift +++ b/Sources/Container.swift @@ -25,19 +25,23 @@ public final class Container { private var resolutionDepth = 0 private let debugHelper: DebugHelper private let defaultObjectScope: ObjectScope + private let synchronized: Bool internal var currentObjectGraph: GraphIdentifier? + internal var graphInstancesInFlight = [ServiceEntryProtocol]() internal let lock: RecursiveLock // Used by SynchronizedResolver. internal var behaviors = [Behavior]() internal init( parent: Container? = nil, debugHelper: DebugHelper, - defaultObjectScope: ObjectScope = .graph + defaultObjectScope: ObjectScope = .graph, + synchronized: Bool = false ) { self.parent = parent self.debugHelper = debugHelper - lock = parent.map { $0.lock } ?? RecursiveLock() + lock = parent.map(\.lock) ?? RecursiveLock() self.defaultObjectScope = defaultObjectScope + self.synchronized = synchronized } /// Instantiates a ``Container`` @@ -63,7 +67,7 @@ public final class Container { /// Removes all registrations in the container. public func removeAll() { - services.removeAll() + syncIfEnabled { services.removeAll() } } /// Discards instances for services registered in the given `ObjectsScopeProtocol`. @@ -74,15 +78,12 @@ public final class Container { /// - Parameters: /// - objectScope: All instances registered in given `ObjectsScopeProtocol` will be discarded. public func resetObjectScope(_ objectScope: ObjectScopeProtocol) { - services.forEachWrite({ (_: ServiceKey, value: ServiceEntryProtocol) in - guard value.objectScope === objectScope else { - return - } - - value.storage.instance = nil - }) - - parent?.resetObjectScope(objectScope) + syncIfEnabled { + services.values + .filter { $0.objectScope === objectScope } + .forEach { $0.storage.instance = nil } + parent?.resetObjectScope(objectScope) + } } /// Discards instances for services registered in the given `ObjectsScope`. It performs the same operation @@ -96,7 +97,42 @@ public final class Container { public func resetObjectScope(_ objectScope: ObjectScope) { resetObjectScope(objectScope as ObjectScopeProtocol) } + /// Discards instances for a given service registered in the given `ObjectsScopeProtocol`. + /// + /// **Example usage:** + /// container.resetObjectScope(ObjectScope.container, MyService.Type) + /// + /// - Parameters: + /// - objectScope: instances registered in given `ObjectsScopeProtocol` + /// - serviceType: and with given serviceType will be discarded. + public func resetObjectScope(_ objectScope: ObjectScopeProtocol, serviceType: Any.Type) { + syncIfEnabled { + let matchingServices = services.keys + .filter { $0.serviceType == serviceType } + .compactMap { services[$0] } + + if matchingServices.isEmpty { return } + + matchingServices + .filter { $0.objectScope === objectScope } + .forEach { $0.storage.instance = nil } + parent?.resetObjectScope(objectScope, serviceType: serviceType) + } + } + /// Discards instances for a given service registered in the given `ObjectsScope`. It performs the same operation + /// as `resetObjectScope(_:ObjectScopeProtocol, serviceType: Any.Type)`, + /// but provides more convenient usage syntax. + /// + /// **Example usage:** + /// container.resetObjectScope(.container, servieType: MyService.self) + /// + /// - Parameters: + /// - objectScope: Instances registered in given `ObjectsScope` + /// - serviceType: and with given serviceType will be discarded. + public func resetObjectScope(_ objectScope: ObjectScope, serviceType: Any.Type) { + resetObjectScope(objectScope as ObjectScopeProtocol, serviceType: serviceType) + } /// Adds a registration for the specified service with the factory closure to specify how the service is /// resolved with dependencies. /// @@ -140,19 +176,35 @@ public final class Container { name: String? = nil, option: ServiceKeyOption? = nil ) -> ServiceEntry { - 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 + syncIfEnabled { + 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) } - behaviors.forEach { $0.container(self, didRegisterType: serviceType, toService: entry, withName: name) } + return entry + } + } - return entry + /// Returns a synchronized view of the container for thread safety. + /// The returned container is ``Resolver`` type and is not the original container. Continuing to add more + /// registrations after calling `synchronize()` will result in different graph scope. + /// + /// It is recommended to call this method after you finish all service registrations to the original container. + /// + /// - Returns: A synchronized container as ``Resolver``. + public func synchronize() -> Resolver { + return Container(parent: self, + debugHelper: debugHelper, + defaultObjectScope: defaultObjectScope, + synchronized: true) } /// Adds behavior to the container. `Behavior.container(_:didRegisterService:withName:)` will be invoked for @@ -161,7 +213,9 @@ public final class Container { /// - Parameters: /// - behavior: Behavior to be added to the container public func addBehavior(_ behavior: Behavior) { - behaviors.append(behavior) + syncIfEnabled { + behaviors.append(behavior) + } } /// Check if a `Service` of a given type and name has already been registered. @@ -176,8 +230,28 @@ public final class Container { of serviceType: Service.Type, name: String? = nil ) -> Bool { - getRegistrations().contains { key, _ in - key.serviceType == serviceType && key.name == name + syncIfEnabled { + services.contains { key, _ in + key.serviceType == serviceType && key.name == name + } || parent?.hasAnyRegistration(of: serviceType, name: name) == true + } + } + + /// Applies a given GraphIdentifier across resolves in the provided closure. + /// - Parameters: + /// - identifier: Graph scope to use + /// - closure: Actions to execute within the Container + /// - Returns: Any value you return (Void otherwise) within the function call. + public func withObjectGraph(_ identifier: GraphIdentifier, closure: (Container) throws -> T) rethrows -> T { + try syncIfEnabled { + let graphIdentifier = currentObjectGraph + defer { + self.currentObjectGraph = graphIdentifier + decrementResolutionDepth() + } + self.currentObjectGraph = identifier + incrementResolutionDepth() + return try closure(self) } } @@ -232,13 +306,15 @@ extension Container: _Resolver { if let entry = getEntry(for: key) { let factory = { [weak self] (graphIdentifier: GraphIdentifier?) -> Any? in - let action = { [weak self] () -> Any? in + self?.syncIfEnabled { [weak self] () -> Any? in + guard let self else { return nil } + let originGraph = self.currentObjectGraph + defer { originGraph.map { self.restoreObjectGraph($0) } } if let graphIdentifier = graphIdentifier { - self?.restoreObjectGraph(graphIdentifier) + self.restoreObjectGraph(graphIdentifier) } - return self?.resolve(entry: entry, invoker: invoker) as Any? + return self.resolve(entry: entry, invoker: invoker) as Any? } - return self?.lock.sync(action: action) } return wrapper.init(inContainer: self, withInstanceFactory: factory) as? Wrapper } else { @@ -275,9 +351,8 @@ extension Container: _Resolver { } fileprivate func graphResolutionCompleted() { - services.forEachWrite { (_, value) in - value.storage.graphResolutionCompleted() - } + graphInstancesInFlight.forEach { $0.storage.graphResolutionCompleted() } + graphInstancesInFlight.removeAll(keepingCapacity: true) currentObjectGraph = nil } } @@ -361,6 +436,12 @@ extension Container: Resolver { return nil } } + + @inline(__always) + @discardableResult + internal func syncIfEnabled(_ action: () throws -> T) rethrows -> T { + try synchronized ? lock.sync(action) : action() + } } // MARK: CustomStringConvertible @@ -372,3 +453,12 @@ extension Container: CustomStringConvertible { + "\n]" } } + +// MARK: Constants + +private extension Container { + static let graphIdentifierKey: ServiceKey = { + let key = ServiceKey(serviceType: GraphIdentifier.self, argumentsType: Resolver.self) + return key + }() +} diff --git a/Sources/Info.plist b/Sources/Info.plist index fa707f75..59988bb4 100644 --- a/Sources/Info.plist +++ b/Sources/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 2.8.4 + 2.10.0 CFBundleSignature ???? CFBundleVersion diff --git a/Sources/ObjectScope.Standard.swift b/Sources/ObjectScope.Standard.swift deleted file mode 100644 index 5ffcb6fc..00000000 --- a/Sources/ObjectScope.Standard.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// Copyright © 2019 Swinject Contributors. All rights reserved. -// - -extension ObjectScope { - /// A new instance is always created by the ``Container`` when a type is resolved. - /// The instance is not shared. - public static let transient = ObjectScope(storageFactory: TransientStorage.init, description: "transient") - - /// Instances are shared only when an object graph is being created, - /// otherwise a new instance is created by the ``Container``. This is the default scope. - public static let graph = ObjectScope(storageFactory: GraphStorage.init, description: "graph") - - /// An instance provided by the ``Container`` is shared within the ``Container`` and its child `Containers`. - public static let container = ObjectScope(storageFactory: PermanentStorage.init, description: "container") - - /// An instance provided by the ``Container`` is shared within the ``Container`` and its child ``Container``s - /// as long as there are strong references to given instance. Otherwise new instance is created - /// when resolving the type. - public static let weak = ObjectScope(storageFactory: WeakStorage.init, description: "weak", - parent: ObjectScope.graph) -} diff --git a/Sources/ObjectScope.swift b/Sources/ObjectScope.swift index d8331ac6..c73ea51f 100644 --- a/Sources/ObjectScope.swift +++ b/Sources/ObjectScope.swift @@ -11,9 +11,9 @@ public protocol ObjectScopeProtocol: AnyObject { } /// Basic implementation of ``ObjectScopeProtocol``. -public class ObjectScope: ObjectScopeProtocol, CustomStringConvertible { - public private(set) var description: String - private var storageFactory: () -> InstanceStorage +public final class ObjectScope: ObjectScopeProtocol, CustomStringConvertible, @unchecked Sendable { + public let description: String + private let storageFactory: () -> InstanceStorage private let parent: ObjectScopeProtocol? /// Instantiates an ``ObjectScope`` with storage factory and description. @@ -31,7 +31,7 @@ public class ObjectScope: ObjectScopeProtocol, CustomStringConvertible { self.parent = parent } - /// Will invoke and return the result of `storageFactory` closure provided during initialisation. + /// Will invoke and return the result of `storageFactory` closure provided during initialization. public func makeStorage() -> InstanceStorage { if let parent = parent { return CompositeStorage([storageFactory(), parent.makeStorage()]) @@ -39,4 +39,22 @@ public class ObjectScope: ObjectScopeProtocol, CustomStringConvertible { return storageFactory() } } + + /// A new instance is always created by the ``Container`` when a type is resolved. + /// The instance is not shared. + public static let transient = ObjectScope(storageFactory: TransientStorage.init, description: "transient") + + /// Instances are shared only when an object graph is being created, + /// otherwise a new instance is created by the ``Container``. This is the default scope. + public static let graph = ObjectScope(storageFactory: GraphStorage.init, description: "graph") + + /// An instance provided by the ``Container`` is shared within the ``Container`` and its child `Containers`. + public static let container = ObjectScope(storageFactory: PermanentStorage.init, description: "container") + + /// An instance provided by the ``Container`` is shared within the ``Container`` and its child ``Container``s + /// as long as there are strong references to given instance. Otherwise new instance is created + /// when resolving the type. + public static let weak = ObjectScope(storageFactory: WeakStorage.init, description: "weak", + parent: ObjectScope.graph) + } diff --git a/Sources/PrivacyInfo.xcprivacy b/Sources/PrivacyInfo.xcprivacy new file mode 100644 index 00000000..7b867651 --- /dev/null +++ b/Sources/PrivacyInfo.xcprivacy @@ -0,0 +1,10 @@ + + + + + NSPrivacyAccessedAPITypes + + NSPrivacyCollectedDataTypes + + + diff --git a/Sources/RecursiveLock.swift b/Sources/RecursiveLock.swift index 48020b83..0ec74c95 100644 --- a/Sources/RecursiveLock.swift +++ b/Sources/RecursiveLock.swift @@ -4,12 +4,100 @@ import Foundation +#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS) +/// `os_unfair_lock_recursive` is, for some reason, a private-API. +/// +/// `RecursiveLock` is a fair, recursive lock where acquisition order is guaranteed and recursion is permitted. +/// +/// Based on readings: +/// - https://www.mikeash.com/pyblog/friday-qa-2017-10-27-locks-thread-safety-and-swift-2017-edition.html +/// - https://github.com/ReactiveCocoa/ReactiveSwift/blob/master/Sources/Atomic.swift +/// - https://serhiybutz.medium.com/swift-mutex-benchmark-b21ee293d9ad +/// +/// Class-type paired with pointer-use guarantees address stability. internal final class RecursiveLock { - private let lock = NSRecursiveLock() + // MARK: Lifecycle - func sync(action: () -> T) -> T { - lock.lock() - defer { lock.unlock() } - return action() + internal init() { + mutex = .allocate(capacity: 1) + mutex.initialize(to: pthread_mutex_t()) + + let attr = UnsafeMutablePointer.allocate(capacity: 1) + attr.initialize(to: pthread_mutexattr_t()) + pthread_mutexattr_init(attr) + pthread_mutexattr_settype(attr, PTHREAD_MUTEX_RECURSIVE) + pthread_mutexattr_setpolicy_np(attr, PTHREAD_MUTEX_POLICY_FIRSTFIT_NP) + + defer { + pthread_mutexattr_destroy(attr) + attr.deinitialize(count: 1) + attr.deallocate() + } + + pthread_mutex_init(mutex, attr) + } + + deinit { + let status = pthread_mutex_destroy(mutex) + assert(status == 0, "Unlock the lock before destroying it") + + mutex.deinitialize(count: 1) + mutex.deallocate() + } + + // MARK: Internal + + internal func lock() { + let status = pthread_mutex_lock(mutex) + switch status { + case 0: + break + case EDEADLK: + fatalError("Lock failed, would cause deadlock") + default: + fatalError("Could not lock") + } + } + + internal func unlock() { + let status = pthread_mutex_unlock(mutex) + switch status { + case 0: + break + case EPERM: + fatalError("Cannot unlock when another thread owns the lock!") + default: + fatalError("Could not unlock") + } + } + + // MARK: Private + + private let mutex: UnsafeMutablePointer +} +#else +internal final class RecursiveLock { + private let recursiveLock = NSRecursiveLock() + + func lock() { + recursiveLock.lock() + } + + func unlock() { + recursiveLock.unlock() + } +} +#endif + +extension RecursiveLock { + /// Guarantee exclusive thread access to certain logic. + /// + /// Claims ownership over this lock within the scope of the closure, + /// during which this thread owns this lock. Nested `atomic` calls + /// on the same thread are permitted. + @discardableResult + func sync(_ block: () throws -> (T)) rethrows -> T { + lock(); defer { unlock() } + return try block() } } diff --git a/Sources/ServiceEntry.swift b/Sources/ServiceEntry.swift index 59914104..c21851f8 100644 --- a/Sources/ServiceEntry.swift +++ b/Sources/ServiceEntry.swift @@ -18,8 +18,8 @@ internal protocol ServiceEntryProtocol: AnyObject { /// As a returned instance from ``Container/register(_:name:factory:)-8gy9r``, 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 + public let serviceType: Any.Type + public let argumentsType: Any.Type internal let factory: FunctionType internal weak var container: Container? diff --git a/Sources/ServiceKey.swift b/Sources/ServiceKey.swift index 87343c3b..8d75acdd 100644 --- a/Sources/ServiceKey.swift +++ b/Sources/ServiceKey.swift @@ -6,14 +6,14 @@ import Foundation // MARK: ServiceKeyOption -public protocol ServiceKeyOption: CustomStringConvertible { +public protocol ServiceKeyOption: CustomStringConvertible, Sendable { func isEqualTo(_ another: ServiceKeyOption) -> Bool func hash(into: inout Hasher) } // MARK: - ServiceKey -internal struct ServiceKey { +internal struct ServiceKey: Sendable { internal let serviceType: Any.Type internal let argumentsType: Any.Type internal let name: String? diff --git a/Sources/ThreadSafeDictionary.swift b/Sources/ThreadSafeDictionary.swift index bc9e6bec..ef51dddf 100644 --- a/Sources/ThreadSafeDictionary.swift +++ b/Sources/ThreadSafeDictionary.swift @@ -67,4 +67,18 @@ internal final class ThreadSafeDictionary { self.internalDictionary.removeAll() } } + + public func contains(where predicate: ((key: KeyType, value: ValueType)) -> Bool) -> Bool { + lock.read { + self.internalDictionary.contains(where: predicate) + } + } + + public var keys: [KeyType] { + lock.read { self.internalDictionary.keys.map { $0 } } + } + + public var values: [ValueType] { + lock.read { self.internalDictionary.values.map { $0 } } + } } diff --git a/Swinject.podspec b/Swinject.podspec index a483f6f1..9d16980c 100644 --- a/Swinject.podspec +++ b/Swinject.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "Swinject" - s.version = "2.8.4" + s.version = "2.10.0" s.summary = "Dependency injection framework for Swift" s.description = "Swinject is a dependency injection framework for Swift, to manage the dependencies of types in your system." @@ -8,12 +8,13 @@ Pod::Spec.new do |s| s.license = 'MIT' s.author = 'Swinject Contributors' s.source = { :git => "https://github.com/Swinject/Swinject.git", :tag => s.version.to_s } + s.resource_bundles = { 'Swinject' => ['Sources/PrivacyInfo.xcprivacy'] } s.swift_version = '5.0' s.source_files = 'Sources/**/*.swift' - s.ios.deployment_target = '11.0' + s.ios.deployment_target = '12.0' s.osx.deployment_target = '10.13' s.watchos.deployment_target = '4.0' - s.tvos.deployment_target = '11.0' + s.tvos.deployment_target = '12.0' end diff --git a/Swinject.xcodeproj/project.pbxproj b/Swinject.xcodeproj/project.pbxproj index 22f3c3d7..9b5bf10b 100644 --- a/Swinject.xcodeproj/project.pbxproj +++ b/Swinject.xcodeproj/project.pbxproj @@ -10,7 +10,6 @@ 0126F47EDE97A611D184682F /* DebugHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE752946EBDAC1CB5823A39E /* DebugHelper.swift */; }; 026337CCA37580CB223C94AD /* ContainerTests.TypeForwarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBDE1F7FCBF0C61DE0BA3ED2 /* ContainerTests.TypeForwarding.swift */; }; 0266A3114C82246F18B52860 /* Food.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1271722CF77709A1173E7863 /* Food.swift */; }; - 055969F9EA3C1AD43B11E006 /* ObjectScope.Standard.swift in Sources */ = {isa = PBXBuildFile; fileRef = A79864FE285C06A91E006806 /* ObjectScope.Standard.swift */; }; 06B6204600E208CA97750825 /* RecursiveLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97ECAF79D15CCE41C49F4590 /* RecursiveLock.swift */; }; 097ACF95FFBE85F427E287AA /* WeakStorageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 185C8B2BAF1CF29EB64159FC /* WeakStorageTests.swift */; }; 0C56E93B497BBA17B0E408F4 /* GraphIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B058F48AF289C3AC307C2F7 /* GraphIdentifier.swift */; }; @@ -36,6 +35,18 @@ 1C084C2AF7B98A21D8B1E35B /* ContainerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19726C4D2E8898E5C05A5E38 /* ContainerTests.swift */; }; 1C1C0CB3F19349057B4FBDE1 /* BasicAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCC59458E04C20587D870946 /* BasicAssembly.swift */; }; 1DB36B1F8919879607F67F35 /* Container.Arguments.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38F57E5E5BE1DC65C3DDAF6 /* Container.Arguments.swift */; }; + 1E7F2E582DDA34A20046B399 /* RecursiveLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E7F2E562DDA34A20046B399 /* RecursiveLock.swift */; }; + 1E7F2E592DDA34A20046B399 /* ThreadSafeDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E7F2E572DDA34A20046B399 /* ThreadSafeDictionary.swift */; }; + 1E7F2E5A2DDA34A20046B399 /* RecursiveLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E7F2E562DDA34A20046B399 /* RecursiveLock.swift */; }; + 1E7F2E5B2DDA34A20046B399 /* ThreadSafeDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E7F2E572DDA34A20046B399 /* ThreadSafeDictionary.swift */; }; + 1E7F2E5C2DDA34A20046B399 /* RecursiveLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E7F2E562DDA34A20046B399 /* RecursiveLock.swift */; }; + 1E7F2E5D2DDA34A20046B399 /* ThreadSafeDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E7F2E572DDA34A20046B399 /* ThreadSafeDictionary.swift */; }; + 1E7F2E5E2DDA34A20046B399 /* RecursiveLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E7F2E562DDA34A20046B399 /* RecursiveLock.swift */; }; + 1E7F2E5F2DDA34A20046B399 /* ThreadSafeDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E7F2E572DDA34A20046B399 /* ThreadSafeDictionary.swift */; }; + 1E7F2E612DDA351D0046B399 /* ReadWriteLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E7F2E602DDA351D0046B399 /* ReadWriteLock.swift */; }; + 1E7F2E622DDA351D0046B399 /* ReadWriteLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E7F2E602DDA351D0046B399 /* ReadWriteLock.swift */; }; + 1E7F2E632DDA351D0046B399 /* ReadWriteLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E7F2E602DDA351D0046B399 /* ReadWriteLock.swift */; }; + 1E7F2E642DDA351D0046B399 /* ReadWriteLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E7F2E602DDA351D0046B399 /* ReadWriteLock.swift */; }; 22873F55E9E82B96A53045C3 /* ContainerTests.CustomStringConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FCE820EE05C206E34CEF068 /* ContainerTests.CustomStringConvertible.swift */; }; 235DD35BC7B8CE15BA46A677 /* BehaviorFakes.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEF07245CC462D98868097A3 /* BehaviorFakes.swift */; }; 23A8D7543ED9973F04C5BC93 /* FunctionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = F388AD8E55D8C6F1E31D0522 /* FunctionType.swift */; }; @@ -81,6 +92,14 @@ 4D667425CB08BF894C1A78AA /* Behavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D8BA4B04A5F517AF663DCE /* Behavior.swift */; }; 5010597DD8C25E6684C8087E /* Assembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5922B783F35F436C528594C1 /* Assembly.swift */; }; 513BDFB32DCE5B048672C33D /* ServiceEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76238B6105E2E443A94CE595 /* ServiceEntry.swift */; }; + 516EB7F82BDC124100FF78D2 /* ContainerTests.Speed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 516EB7F72BDC124100FF78D2 /* ContainerTests.Speed.swift */; }; + 516EB7F92BDC124100FF78D2 /* ContainerTests.Speed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 516EB7F72BDC124100FF78D2 /* ContainerTests.Speed.swift */; }; + 516EB7FA2BDC124100FF78D2 /* ContainerTests.Speed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 516EB7F72BDC124100FF78D2 /* ContainerTests.Speed.swift */; }; + 516EB7FB2BDC124100FF78D2 /* ContainerTests.Speed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 516EB7F72BDC124100FF78D2 /* ContainerTests.Speed.swift */; }; + 51F254202BC5A2EF003E3BCD /* ThreadSafeDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51F2541B2BC5A2EF003E3BCD /* ThreadSafeDictionary.swift */; }; + 51F254212BC5A2EF003E3BCD /* ThreadSafeDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51F2541B2BC5A2EF003E3BCD /* ThreadSafeDictionary.swift */; }; + 51F254222BC5A2EF003E3BCD /* ThreadSafeDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51F2541B2BC5A2EF003E3BCD /* ThreadSafeDictionary.swift */; }; + 51F254232BC5A2EF003E3BCD /* ThreadSafeDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51F2541B2BC5A2EF003E3BCD /* ThreadSafeDictionary.swift */; }; 52E4C2C279904E90D5F37204 /* Container.swift in Sources */ = {isa = PBXBuildFile; fileRef = 172E48E07BA72BCBFB305E93 /* Container.swift */; }; 545B9E4AD1990F07C3C8AB5E /* ContainerTests.GraphCaching.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46A04FC6931B56743E4B7D63 /* ContainerTests.GraphCaching.swift */; }; 5488A7839EF00BAC43CE2CEE /* Container.TypeForwarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7605BDEF71547D0B17D7195A /* Container.TypeForwarding.swift */; }; @@ -110,7 +129,6 @@ 7000D01DCB05BF57BC89BCF8 /* InstanceWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7101AB0DE88A5340F7EAAC04 /* InstanceWrapper.swift */; }; 706A459CAE24E0D5054CEC30 /* GraphIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B058F48AF289C3AC307C2F7 /* GraphIdentifier.swift */; }; 73390576F317FC0A851046B8 /* ServiceEntryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28B6980B5294739C0656769C /* ServiceEntryTests.swift */; }; - 737740CDFB89189DFF5FD165 /* Swinject.h in Headers */ = {isa = PBXBuildFile; fileRef = 74DE57FB3E8228904E6FE0D7 /* Swinject.h */; settings = {ATTRIBUTES = (Public, ); }; }; 73906701DF9BE9870A55F291 /* ServiceKeyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CCDBC7E5186CB36CD160D94 /* ServiceKeyTests.swift */; }; 75A776D4072BCF74F298D818 /* EmploymentAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 077047532310E42432E94D83 /* EmploymentAssembly.swift */; }; 75DC16A87FD15168ACDEEAA3 /* LazyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7287A8057A58B72EBC5C8CB9 /* LazyTests.swift */; }; @@ -160,9 +178,7 @@ BAB2886500919D428F97215A /* DebugHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE752946EBDAC1CB5823A39E /* DebugHelper.swift */; }; BAB510EEEBDD444BA65E0003 /* LazyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7287A8057A58B72EBC5C8CB9 /* LazyTests.swift */; }; BB78B5DA95DCE3A942C18910 /* InstanceWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7101AB0DE88A5340F7EAAC04 /* InstanceWrapper.swift */; }; - BCD130E9F1D33C66AA6A12F7 /* Swinject.h in Headers */ = {isa = PBXBuildFile; fileRef = 74DE57FB3E8228904E6FE0D7 /* Swinject.h */; settings = {ATTRIBUTES = (Public, ); }; }; BCDBFF75F368C980B6DA4BFE /* ContainerTests.Behavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = 988A20A0815159E43C26CA46 /* ContainerTests.Behavior.swift */; }; - BDCBFD62903A1C0F8B35797C /* ObjectScope.Standard.swift in Sources */ = {isa = PBXBuildFile; fileRef = A79864FE285C06A91E006806 /* ObjectScope.Standard.swift */; }; BE3889327CE4A24631B91350 /* AssemblerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29EB588ED052D3BAF38AFBBE /* AssemblerTests.swift */; }; BE3A8FAC5AC745EDCCD5A5FB /* Swinject.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 6D54F152C11C966ECFC55ECB /* Swinject.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; BF6475BEA46F81B30A6FA19E /* Container.swift in Sources */ = {isa = PBXBuildFile; fileRef = 172E48E07BA72BCBFB305E93 /* Container.swift */; }; @@ -175,7 +191,6 @@ C7C1DD107809E8C3C728C199 /* ContainerTests.DebugHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4744C3ABBA9A8A585C726883 /* ContainerTests.DebugHelper.swift */; }; CC64B74A022612990F57D51D /* GraphIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B058F48AF289C3AC307C2F7 /* GraphIdentifier.swift */; }; CF05649033EABCF21B15C535 /* DebugHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE752946EBDAC1CB5823A39E /* DebugHelper.swift */; }; - D0D71F9C22A0EE82B6E4F61A /* Swinject.h in Headers */ = {isa = PBXBuildFile; fileRef = 74DE57FB3E8228904E6FE0D7 /* Swinject.h */; settings = {ATTRIBUTES = (Public, ); }; }; D210E7349E119368A741DB2F /* LoadAwareAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2380F40FC2B9229F36B13679 /* LoadAwareAssembly.swift */; }; D4D93174FF22D805953A727A /* _Resolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15C304EFDAFB81043B2896E5 /* _Resolver.swift */; }; D56BD23EC91E28CE6C6D6E78 /* Container.swift in Sources */ = {isa = PBXBuildFile; fileRef = 172E48E07BA72BCBFB305E93 /* Container.swift */; }; @@ -191,7 +206,6 @@ EBB561398EE319A46C487059 /* ContainerTests.CustomScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7608AD07FC553DAC2911FB /* ContainerTests.CustomScope.swift */; }; ED19CAF7B39978B3CDF2013E /* Person.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7B00D2ED19209D0C6210169 /* Person.swift */; }; ED97A21AE7F99626D9E8BB80 /* ContainerTests.CustomStringConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FCE820EE05C206E34CEF068 /* ContainerTests.CustomStringConvertible.swift */; }; - EE0D3637D2524AC1CD21780D /* Swinject.h in Headers */ = {isa = PBXBuildFile; fileRef = 74DE57FB3E8228904E6FE0D7 /* Swinject.h */; settings = {ATTRIBUTES = (Public, ); }; }; EE4786524E79B10DB36FDB11 /* Resolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC379E27E9804FC6C0BA0842 /* Resolver.swift */; }; F355D8940486AF9DE89DD22E /* Circularity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47328731EED63322AD76FB3A /* Circularity.swift */; }; F73BFA36FB4432C826A3785C /* WeakStorageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 185C8B2BAF1CF29EB64159FC /* WeakStorageTests.swift */; }; @@ -199,11 +213,9 @@ F945C7963B1566A1C3DAC3FA /* SynchronizedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6E0A3F26E3718902E420D8E /* SynchronizedTests.swift */; }; F98A1B2A226EE26A13C67F34 /* FunctionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = F388AD8E55D8C6F1E31D0522 /* FunctionType.swift */; }; FA6DD52FA4D4BB157A43CBEE /* _Resolver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15C304EFDAFB81043B2896E5 /* _Resolver.swift */; }; - FA89EFC16AEAC2EC333CEA81 /* ObjectScope.Standard.swift in Sources */ = {isa = PBXBuildFile; fileRef = A79864FE285C06A91E006806 /* ObjectScope.Standard.swift */; }; FCC32CC413C08CF94D7F661E /* Person.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7B00D2ED19209D0C6210169 /* Person.swift */; }; FCF3A63712ECD9E5BE371DC7 /* SynchronizedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6E0A3F26E3718902E420D8E /* SynchronizedTests.swift */; }; FE07C0CCCD45639FBF85A456 /* Behavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8D8BA4B04A5F517AF663DCE /* Behavior.swift */; }; - FEAF6DE7BBDD922B61E0ED20 /* ObjectScope.Standard.swift in Sources */ = {isa = PBXBuildFile; fileRef = A79864FE285C06A91E006806 /* ObjectScope.Standard.swift */; }; FED7D8B8C74876D03B5D09DE /* Assembler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 944B981A9157833AC3397B4A /* Assembler.swift */; }; FF222640214C9F4DA56130C4 /* InstanceStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B7688D6F1E3466891D0582E /* InstanceStorage.swift */; }; FF9DCB0AB20B0DBBE79451BB /* BehaviorFakes.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEF07245CC462D98868097A3 /* BehaviorFakes.swift */; }; @@ -298,6 +310,9 @@ 185C8B2BAF1CF29EB64159FC /* WeakStorageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeakStorageTests.swift; sourceTree = ""; }; 19726C4D2E8898E5C05A5E38 /* ContainerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainerTests.swift; sourceTree = ""; }; 1C7608AD07FC553DAC2911FB /* ContainerTests.CustomScope.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainerTests.CustomScope.swift; sourceTree = ""; }; + 1E7F2E562DDA34A20046B399 /* RecursiveLock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecursiveLock.swift; sourceTree = ""; }; + 1E7F2E572DDA34A20046B399 /* ThreadSafeDictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadSafeDictionary.swift; sourceTree = ""; }; + 1E7F2E602DDA351D0046B399 /* ReadWriteLock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadWriteLock.swift; sourceTree = ""; }; 2380F40FC2B9229F36B13679 /* LoadAwareAssembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadAwareAssembly.swift; sourceTree = ""; }; 28B6980B5294739C0656769C /* ServiceEntryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceEntryTests.swift; sourceTree = ""; }; 29EB588ED052D3BAF38AFBBE /* AssemblerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssemblerTests.swift; sourceTree = ""; }; @@ -307,6 +322,9 @@ 46A04FC6931B56743E4B7D63 /* ContainerTests.GraphCaching.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainerTests.GraphCaching.swift; sourceTree = ""; }; 47328731EED63322AD76FB3A /* Circularity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Circularity.swift; sourceTree = ""; }; 4744C3ABBA9A8A585C726883 /* ContainerTests.DebugHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainerTests.DebugHelper.swift; sourceTree = ""; }; + 515B0F492BC9AF5D00C4E24F /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; + 516EB7F72BDC124100FF78D2 /* ContainerTests.Speed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainerTests.Speed.swift; sourceTree = ""; }; + 51F2541B2BC5A2EF003E3BCD /* ThreadSafeDictionary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThreadSafeDictionary.swift; sourceTree = ""; }; 54FFC812F14E9976208B644F /* ServiceEntry.TypeForwarding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceEntry.TypeForwarding.swift; sourceTree = ""; }; 5922B783F35F436C528594C1 /* Assembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Assembly.swift; sourceTree = ""; }; 5F7BC1C4169BB4382C6D3E1F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; @@ -316,7 +334,6 @@ 6D54F152C11C966ECFC55ECB /* Swinject.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Swinject.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 7101AB0DE88A5340F7EAAC04 /* InstanceWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstanceWrapper.swift; sourceTree = ""; }; 7287A8057A58B72EBC5C8CB9 /* LazyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LazyTests.swift; sourceTree = ""; }; - 74DE57FB3E8228904E6FE0D7 /* Swinject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Swinject.h; sourceTree = ""; }; 7605BDEF71547D0B17D7195A /* Container.TypeForwarding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Container.TypeForwarding.swift; sourceTree = ""; }; 76238B6105E2E443A94CE595 /* ServiceEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceEntry.swift; sourceTree = ""; }; 8B9785AAE94A5447FA307242 /* Swinject.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Swinject.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -328,7 +345,6 @@ 9B058F48AF289C3AC307C2F7 /* GraphIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphIdentifier.swift; sourceTree = ""; }; A20C1319AF31EC7F8E6945FE /* SwinjectTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwinjectTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; A28176E7C90C61FB8131FE06 /* ProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProviderTests.swift; sourceTree = ""; }; - A79864FE285C06A91E006806 /* ObjectScope.Standard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObjectScope.Standard.swift; sourceTree = ""; }; A982F3108666D12EA0810D52 /* .swiftlint.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = .swiftlint.yml; sourceTree = ""; }; AEAC51C6D09DEBE863D5A06E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; B0F839BCDE52371FE49454B9 /* Container.Logging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Container.Logging.swift; sourceTree = ""; }; @@ -409,6 +425,7 @@ 5FCE820EE05C206E34CEF068 /* ContainerTests.CustomStringConvertible.swift */, 4744C3ABBA9A8A585C726883 /* ContainerTests.DebugHelper.swift */, 46A04FC6931B56743E4B7D63 /* ContainerTests.GraphCaching.swift */, + 516EB7F72BDC124100FF78D2 /* ContainerTests.Speed.swift */, 19726C4D2E8898E5C05A5E38 /* ContainerTests.swift */, BBDE1F7FCBF0C61DE0BA3ED2 /* ContainerTests.TypeForwarding.swift */, 077047532310E42432E94D83 /* EmploymentAssembly.swift */, @@ -459,6 +476,8 @@ D026A6699A2A932511D29E14 /* Sources */ = { isa = PBXGroup; children = ( + 515B0F492BC9AF5D00C4E24F /* PrivacyInfo.xcprivacy */, + 51F2541B2BC5A2EF003E3BCD /* ThreadSafeDictionary.swift */, 15C304EFDAFB81043B2896E5 /* _Resolver.swift */, 944B981A9157833AC3397B4A /* Assembler.swift */, 5922B783F35F436C528594C1 /* Assembly.swift */, @@ -468,19 +487,20 @@ 172E48E07BA72BCBFB305E93 /* Container.swift */, 7605BDEF71547D0B17D7195A /* Container.TypeForwarding.swift */, DE752946EBDAC1CB5823A39E /* DebugHelper.swift */, + 1E7F2E562DDA34A20046B399 /* RecursiveLock.swift */, + 1E7F2E572DDA34A20046B399 /* ThreadSafeDictionary.swift */, + 1E7F2E602DDA351D0046B399 /* ReadWriteLock.swift */, F388AD8E55D8C6F1E31D0522 /* FunctionType.swift */, 9B058F48AF289C3AC307C2F7 /* GraphIdentifier.swift */, 5F7BC1C4169BB4382C6D3E1F /* Info.plist */, 3B7688D6F1E3466891D0582E /* InstanceStorage.swift */, 7101AB0DE88A5340F7EAAC04 /* InstanceWrapper.swift */, - A79864FE285C06A91E006806 /* ObjectScope.Standard.swift */, 957AFDACC07687608E5E5F7E /* ObjectScope.swift */, 97ECAF79D15CCE41C49F4590 /* RecursiveLock.swift */, EC379E27E9804FC6C0BA0842 /* Resolver.swift */, 76238B6105E2E443A94CE595 /* ServiceEntry.swift */, 54FFC812F14E9976208B644F /* ServiceEntry.TypeForwarding.swift */, BD2ED5B0128132DCD709777F /* ServiceKey.swift */, - 74DE57FB3E8228904E6FE0D7 /* Swinject.h */, 39924B830576F62A4B528A37 /* UnavailableItems.swift */, ); path = Sources; @@ -493,7 +513,6 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - BCD130E9F1D33C66AA6A12F7 /* Swinject.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -501,7 +520,6 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 737740CDFB89189DFF5FD165 /* Swinject.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -509,7 +527,6 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - D0D71F9C22A0EE82B6E4F61A /* Swinject.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -517,7 +534,6 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - EE0D3637D2524AC1CD21780D /* Swinject.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -816,9 +832,12 @@ buildActionMask = 2147483647; files = ( 602201FE3E6CC64F594DEBA1 /* Assembler.swift in Sources */, + 1E7F2E5A2DDA34A20046B399 /* RecursiveLock.swift in Sources */, + 1E7F2E5B2DDA34A20046B399 /* ThreadSafeDictionary.swift in Sources */, A5D9F0A6D8FC89662658FBF3 /* Assembly.swift in Sources */, FE07C0CCCD45639FBF85A456 /* Behavior.swift in Sources */, 9FF7BABC0BA21A89A755E37C /* Container.Arguments.swift in Sources */, + 1E7F2E632DDA351D0046B399 /* ReadWriteLock.swift in Sources */, 363C4230CAC4547E7A676249 /* Container.Logging.swift in Sources */, 1B36EE582AD6251A33C956F2 /* Container.TypeForwarding.swift in Sources */, 4A1AEFDC62BC395924AB2355 /* Container.swift in Sources */, @@ -827,12 +846,12 @@ 706A459CAE24E0D5054CEC30 /* GraphIdentifier.swift in Sources */, B55E915211F19C91C622E068 /* InstanceStorage.swift in Sources */, BB78B5DA95DCE3A942C18910 /* InstanceWrapper.swift in Sources */, - 055969F9EA3C1AD43B11E006 /* ObjectScope.Standard.swift in Sources */, 62A1539A3B07EE3E1B72CF95 /* ObjectScope.swift in Sources */, 06B6204600E208CA97750825 /* RecursiveLock.swift in Sources */, 5BB768EFEB4BA7D1D05B4DCC /* Resolver.swift in Sources */, 3D86E87634E427DCE7A8CF81 /* ServiceEntry.TypeForwarding.swift in Sources */, 513BDFB32DCE5B048672C33D /* ServiceEntry.swift in Sources */, + 51F254212BC5A2EF003E3BCD /* ThreadSafeDictionary.swift in Sources */, A39172D39FE39D24A12A7257 /* ServiceKey.swift in Sources */, 68DA3B5FB308092FE9B5C733 /* UnavailableItems.swift in Sources */, 138D38987ED00235C384DD26 /* _Resolver.swift in Sources */, @@ -848,6 +867,7 @@ 1C1C0CB3F19349057B4FBDE1 /* BasicAssembly.swift in Sources */, 235DD35BC7B8CE15BA46A677 /* BehaviorFakes.swift in Sources */, F355D8940486AF9DE89DD22E /* Circularity.swift in Sources */, + 516EB7F82BDC124100FF78D2 /* ContainerTests.Speed.swift in Sources */, 374D3B4A2A2163726B4E55BC /* ContainerTests.Arguments.swift in Sources */, C578E997A0076FB320475132 /* ContainerTests.Behavior.swift in Sources */, 4C06628453523BB76531404F /* ContainerTests.Circularity.swift in Sources */, @@ -880,6 +900,7 @@ 9ECC88CB09E13FD179A1ED8E /* BasicAssembly.swift in Sources */, FF9DCB0AB20B0DBBE79451BB /* BehaviorFakes.swift in Sources */, F82A2357F3C86D24E1E1D712 /* Circularity.swift in Sources */, + 516EB7F92BDC124100FF78D2 /* ContainerTests.Speed.swift in Sources */, 96E113959C6AF4C512C95B0F /* ContainerTests.Arguments.swift in Sources */, 31C021202AAC21C893F790A9 /* ContainerTests.Behavior.swift in Sources */, DAB7F0C574E1C33C92C455A5 /* ContainerTests.Circularity.swift in Sources */, @@ -912,6 +933,7 @@ 6443FB8C5B3DD95740287398 /* BasicAssembly.swift in Sources */, 0CAD0368F908D3D285C6A9A9 /* BehaviorFakes.swift in Sources */, 69A27AA36C90A4D4A5FDDEFC /* Circularity.swift in Sources */, + 516EB7FB2BDC124100FF78D2 /* ContainerTests.Speed.swift in Sources */, 56F7004F323632D46B60D750 /* ContainerTests.Arguments.swift in Sources */, BCDBFF75F368C980B6DA4BFE /* ContainerTests.Behavior.swift in Sources */, 88D3B360E738AE936A4C3FC1 /* ContainerTests.Circularity.swift in Sources */, @@ -944,6 +966,7 @@ 5D17DB72B4986D174D69135B /* BasicAssembly.swift in Sources */, 1BA2596EFB6E7BF4D46E3C9D /* BehaviorFakes.swift in Sources */, 0E5336910C7B0A00E588940E /* Circularity.swift in Sources */, + 516EB7FA2BDC124100FF78D2 /* ContainerTests.Speed.swift in Sources */, A87B2787A32FAA3254700F90 /* ContainerTests.Arguments.swift in Sources */, 12984E4749F7C882055D380F /* ContainerTests.Behavior.swift in Sources */, 0CC89E82308CF2FFF0CCC267 /* ContainerTests.Circularity.swift in Sources */, @@ -972,9 +995,12 @@ buildActionMask = 2147483647; files = ( 474A4D73269D7BDF0844D704 /* Assembler.swift in Sources */, + 1E7F2E582DDA34A20046B399 /* RecursiveLock.swift in Sources */, + 1E7F2E592DDA34A20046B399 /* ThreadSafeDictionary.swift in Sources */, 81AE1BCE31BC99440151A68F /* Assembly.swift in Sources */, 2C838FEC75D618B575750A17 /* Behavior.swift in Sources */, 1DB36B1F8919879607F67F35 /* Container.Arguments.swift in Sources */, + 1E7F2E642DDA351D0046B399 /* ReadWriteLock.swift in Sources */, 9D78DAAC0307D9422C501D33 /* Container.Logging.swift in Sources */, 5488A7839EF00BAC43CE2CEE /* Container.TypeForwarding.swift in Sources */, D56BD23EC91E28CE6C6D6E78 /* Container.swift in Sources */, @@ -983,12 +1009,12 @@ 59AB5E84FD9B11B7D1CA2401 /* GraphIdentifier.swift in Sources */, FF222640214C9F4DA56130C4 /* InstanceStorage.swift in Sources */, 7000D01DCB05BF57BC89BCF8 /* InstanceWrapper.swift in Sources */, - FEAF6DE7BBDD922B61E0ED20 /* ObjectScope.Standard.swift in Sources */, B9566410214991FBA727BB37 /* ObjectScope.swift in Sources */, C7A673429D2B735BAC18F58E /* RecursiveLock.swift in Sources */, EE4786524E79B10DB36FDB11 /* Resolver.swift in Sources */, 54A3ED20B6A9506B9D514098 /* ServiceEntry.TypeForwarding.swift in Sources */, 1A2759577A52C96E28BB44F0 /* ServiceEntry.swift in Sources */, + 51F254222BC5A2EF003E3BCD /* ThreadSafeDictionary.swift in Sources */, AEE58DEFB1764391B49E4EA0 /* ServiceKey.swift in Sources */, 58654C80A0946909D44F6BAD /* UnavailableItems.swift in Sources */, D4D93174FF22D805953A727A /* _Resolver.swift in Sources */, @@ -1000,9 +1026,12 @@ buildActionMask = 2147483647; files = ( 8F8BF2FFD2D666C4EE71E796 /* Assembler.swift in Sources */, + 1E7F2E5E2DDA34A20046B399 /* RecursiveLock.swift in Sources */, + 1E7F2E5F2DDA34A20046B399 /* ThreadSafeDictionary.swift in Sources */, 695E6FF61B8CD35434685835 /* Assembly.swift in Sources */, 4D667425CB08BF894C1A78AA /* Behavior.swift in Sources */, 5BAC0A607F822D6205DA6178 /* Container.Arguments.swift in Sources */, + 1E7F2E622DDA351D0046B399 /* ReadWriteLock.swift in Sources */, 40FCA2AB08F4EA23096075AB /* Container.Logging.swift in Sources */, 1AF1BB032596F2ADF9021F90 /* Container.TypeForwarding.swift in Sources */, 52E4C2C279904E90D5F37204 /* Container.swift in Sources */, @@ -1011,12 +1040,12 @@ CC64B74A022612990F57D51D /* GraphIdentifier.swift in Sources */, D6B0E0FA93AD8D47AA07AE03 /* InstanceStorage.swift in Sources */, 6A352D6A2C12D7BDABC38645 /* InstanceWrapper.swift in Sources */, - BDCBFD62903A1C0F8B35797C /* ObjectScope.Standard.swift in Sources */, 130DDD2347169F885F420989 /* ObjectScope.swift in Sources */, 48B5EC6BADDE7B88260ADE44 /* RecursiveLock.swift in Sources */, 9CD3F07823D2E64DD636E00A /* Resolver.swift in Sources */, 1845CF466289264A5BBC0CCE /* ServiceEntry.TypeForwarding.swift in Sources */, 35C9BCE88B6D6567760D7389 /* ServiceEntry.swift in Sources */, + 51F254232BC5A2EF003E3BCD /* ThreadSafeDictionary.swift in Sources */, 3957BFF436703E5C0434D41E /* ServiceKey.swift in Sources */, 95070453A9934F08F9E02E6C /* UnavailableItems.swift in Sources */, FA6DD52FA4D4BB157A43CBEE /* _Resolver.swift in Sources */, @@ -1028,9 +1057,12 @@ buildActionMask = 2147483647; files = ( FED7D8B8C74876D03B5D09DE /* Assembler.swift in Sources */, + 1E7F2E5C2DDA34A20046B399 /* RecursiveLock.swift in Sources */, + 1E7F2E5D2DDA34A20046B399 /* ThreadSafeDictionary.swift in Sources */, 5010597DD8C25E6684C8087E /* Assembly.swift in Sources */, C60108843AA83DF2B408EE87 /* Behavior.swift in Sources */, AD91C0A080A7CE74369407E7 /* Container.Arguments.swift in Sources */, + 1E7F2E612DDA351D0046B399 /* ReadWriteLock.swift in Sources */, 77E67A2C566A1DFD5407BBA4 /* Container.Logging.swift in Sources */, 0F6B596CC2F819EF9CF5FE75 /* Container.TypeForwarding.swift in Sources */, BF6475BEA46F81B30A6FA19E /* Container.swift in Sources */, @@ -1039,12 +1071,12 @@ 0C56E93B497BBA17B0E408F4 /* GraphIdentifier.swift in Sources */, AB05847EAB8D85A8679B5EC5 /* InstanceStorage.swift in Sources */, 61357D47A1C4870FAA34377C /* InstanceWrapper.swift in Sources */, - FA89EFC16AEAC2EC333CEA81 /* ObjectScope.Standard.swift in Sources */, 40DCC9D2F3ABC2B36C9DC8AE /* ObjectScope.swift in Sources */, 8B9E356593059568E55F9B06 /* RecursiveLock.swift in Sources */, 96BA7CCC6AEC192CAD3054E1 /* Resolver.swift in Sources */, 1120EBEC146D1EDDCC29AB17 /* ServiceEntry.TypeForwarding.swift in Sources */, 808983B2AF095E481615029E /* ServiceEntry.swift in Sources */, + 51F254202BC5A2EF003E3BCD /* ThreadSafeDictionary.swift in Sources */, E28F56015BFBB47A791856D3 /* ServiceKey.swift in Sources */, 4D631FA98F95F809740D6585 /* UnavailableItems.swift in Sources */, 7E57CE64E1356423F0F89FD3 /* _Resolver.swift in Sources */, @@ -1177,6 +1209,7 @@ RUN_DOCUMENTATION_COMPILER = YES; SDKROOT = watchos; SKIP_INSTALL = YES; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = 4; VERSIONING_SYSTEM = "apple-generic"; }; @@ -1205,6 +1238,7 @@ RUN_DOCUMENTATION_COMPILER = YES; SDKROOT = macosx; SKIP_INSTALL = YES; + SWIFT_VERSION = 6.0; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; @@ -1248,6 +1282,7 @@ RUN_DOCUMENTATION_COMPILER = YES; SDKROOT = appletvos; SKIP_INSTALL = YES; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = 3; VERSIONING_SYSTEM = "apple-generic"; }; @@ -1305,6 +1340,7 @@ RUN_DOCUMENTATION_COMPILER = YES; SDKROOT = watchos; SKIP_INSTALL = YES; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = 4; VERSIONING_SYSTEM = "apple-generic"; }; @@ -1390,6 +1426,7 @@ RUN_DOCUMENTATION_COMPILER = YES; SDKROOT = appletvos; SKIP_INSTALL = YES; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = 3; VERSIONING_SYSTEM = "apple-generic"; }; @@ -1426,6 +1463,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1435,6 +1473,7 @@ RUN_DOCUMENTATION_COMPILER = YES; SDKROOT = iphoneos; SKIP_INSTALL = YES; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; @@ -1515,6 +1554,7 @@ RUN_DOCUMENTATION_COMPILER = YES; SDKROOT = macosx; SKIP_INSTALL = YES; + SWIFT_VERSION = 6.0; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; @@ -1532,6 +1572,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1541,6 +1582,7 @@ RUN_DOCUMENTATION_COMPILER = YES; SDKROOT = iphoneos; SKIP_INSTALL = YES; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; diff --git a/Swinject.xcodeproj/xcshareddata/xcschemes/Swinject-iOS.xcscheme b/Swinject.xcodeproj/xcshareddata/xcschemes/Swinject-iOS.xcscheme index 86b638de..84e8918a 100644 --- a/Swinject.xcodeproj/xcshareddata/xcschemes/Swinject-iOS.xcscheme +++ b/Swinject.xcodeproj/xcshareddata/xcschemes/Swinject-iOS.xcscheme @@ -26,8 +26,16 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - onlyGenerateCoverageForSpecifiedTargets = "NO" shouldUseLaunchSchemeArgsEnv = "YES"> + + + + @@ -40,17 +48,6 @@ - - - - - - - - - - diff --git a/Swinject.xcodeproj/xcshareddata/xcschemes/Swinject-macOS.xcscheme b/Swinject.xcodeproj/xcshareddata/xcschemes/Swinject-macOS.xcscheme index a8a1a12f..3bcbe2da 100644 --- a/Swinject.xcodeproj/xcshareddata/xcschemes/Swinject-macOS.xcscheme +++ b/Swinject.xcodeproj/xcshareddata/xcschemes/Swinject-macOS.xcscheme @@ -26,8 +26,16 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - onlyGenerateCoverageForSpecifiedTargets = "NO" shouldUseLaunchSchemeArgsEnv = "YES"> + + + + @@ -40,17 +48,6 @@ - - - - - - - - - - diff --git a/Tests/SwinjectTests/Circularity.swift b/Tests/SwinjectTests/Circularity.swift index e9018dd0..8a198237 100644 --- a/Tests/SwinjectTests/Circularity.swift +++ b/Tests/SwinjectTests/Circularity.swift @@ -3,6 +3,7 @@ // import Foundation +import Swinject // MARK: Circular dependency of two objects @@ -69,3 +70,35 @@ internal class DDependingOnBC: D { internal class CDependingOnWeakB: C { weak var b: B? } + +internal protocol LazyParentProtocol { + var child1: LazyChildProtocol { get } + var child2: LazyChildProtocol { get } +} +internal protocol LazyChildProtocol: AnyObject { + var lazy: Lazy { get } +} +internal protocol LazySingletonProtocol { + var lazy: Lazy { get } +} +internal protocol LazilyResolvedProtocol: AnyObject { } + +internal class LazyParent: LazyParentProtocol { + let child1: LazyChildProtocol + let child2: LazyChildProtocol + + init(child1: LazyChildProtocol, child2: LazyChildProtocol) { + self.child1 = child1 + self.child2 = child2 + } +} + +internal class LazyChild: LazyChildProtocol, LazySingletonProtocol { + let lazy: Lazy + + init(lazy: Lazy) { + self.lazy = lazy + } +} + +internal class LazilyResolved: LazilyResolvedProtocol { } diff --git a/Tests/SwinjectTests/ContainerTests.CustomScope.swift b/Tests/SwinjectTests/ContainerTests.CustomScope.swift index 77285529..3e3ab92f 100644 --- a/Tests/SwinjectTests/ContainerTests.CustomScope.swift +++ b/Tests/SwinjectTests/ContainerTests.CustomScope.swift @@ -83,8 +83,75 @@ class ContainerTests_CustomScope: XCTestCase { XCTAssertNil(storage.instance) } -} + // MARK: Reseting scope with given Service Type + + func testResetObjectScopeRemovesOnlyMatchingScopeInstances() { + let scope = ObjectScope.container + + container.register(Foo.self) { _ in Foo() }.inObjectScope(scope) + let instance = container.resolve(Foo.self) + + container.resetObjectScope(scope, serviceType: Foo.self) + let instanceAfterReset = container.resolve(Foo.self) + + XCTAssertTrue(instance !== instanceAfterReset) + } + func testResetObjectScopeDoesNotRemoveInstancesOfDifferentScopes() { + let containerScope = ObjectScope.container + let graphScope = ObjectScope.graph + + container.register(Foo.self, name: "containerScoped") { _ in Foo() }.inObjectScope(containerScope) + container.register(Foo.self, name: "graphScoped") { _ in Foo() }.inObjectScope(graphScope) + + let containerInstance = container.resolve(Foo.self, name: "containerScoped") + let graphInstance = container.resolve(Foo.self, name: "graphScoped") + + XCTAssertNotNil(graphInstance) + + container.resetObjectScope(graphScope, serviceType: Foo.self) + let containerInstanceAfterReset = container.resolve(Foo.self, name: "containerScoped") // container-scoped + + XCTAssertTrue(containerInstance === containerInstanceAfterReset) + } + func testResetObjectScopeDoesNotRemoveInstancesOfDifferentTypes() { + let scope = ObjectScope.container + + container.register(Foo.self) { _ in Foo() }.inObjectScope(scope) + container.register(Bar.self) { _ in Bar() }.inObjectScope(scope) + + let fooInstance = container.resolve(Foo.self) + let barInstance = container.resolve(Bar.self) + + container.resetObjectScope(scope, serviceType: Foo.self) + let newFooInstance = container.resolve(Foo.self) + let newBarInstance = container.resolve(Bar.self) + + XCTAssertTrue(fooInstance !== newFooInstance) + XCTAssertTrue(barInstance === newBarInstance) + } + func testResetObjectScopeCallsParentContainer() { + let parentContainer = Container() + let childContainer = Container(parent: parentContainer) + + let scope = ObjectScope.container + + parentContainer.register(Foo.self) { _ in Foo() }.inObjectScope(scope) + childContainer.register(Foo.self) { _ in Foo() }.inObjectScope(scope) + + let parentInstance = parentContainer.resolve(Foo.self) + let childInstance = childContainer.resolve(Foo.self) + + childContainer.resetObjectScope(scope, serviceType: Foo.self) + let newParentInstance = parentContainer.resolve(Foo.self) + let newChildInstance = childContainer.resolve(Foo.self) + + XCTAssertFalse(childInstance === newChildInstance) + XCTAssertFalse(parentInstance === newParentInstance) + } +} +private class Foo {} +private class Bar {} private class FakeStorage: InstanceStorage { var instance: Any? } diff --git a/Tests/SwinjectTests/ContainerTests.Speed.swift b/Tests/SwinjectTests/ContainerTests.Speed.swift new file mode 100644 index 00000000..8736a3bb --- /dev/null +++ b/Tests/SwinjectTests/ContainerTests.Speed.swift @@ -0,0 +1,54 @@ +// +// Copyright © 2024 Swinject Contributors. All rights reserved. +// + +import XCTest +@testable import Swinject + +/// Not a perfect way to measure speed improvements, especially with all the different hardware that will be running +/// this test, but good to run before/after changes to see changes. +@available(iOS 13.0, *) +class ContainerSpeedTests: XCTestCase { + + var container: Container! + override func setUpWithError() throws { + container = Container() + + container.register(Animal.self) { _ in Cat() } + container.register(Animal.self) { _, arg in Cat(name: arg) } + container.register(Animal.self) { _, arg1, arg2 in Cat(name: arg1, sleeping: arg2) } + } + + // MARK: General speed test, ran locally for testing purposes + + func testContainerDefaultResolvesByArguments() { + let measureOptions = XCTMeasureOptions() + measureOptions.iterationCount = 1 + + measure(options: measureOptions) { + container.resolveCats() + } + } + + func testContainerSyncResolvesByArguments() { + container = container.synchronize() as? Container + + let measureOptions = XCTMeasureOptions() + measureOptions.iterationCount = 1 + + measure(options: measureOptions) { + container.resolveCats() + } + } +} + +fileprivate extension Container { + func resolveCats() { + for _ in 0..<500_000 { + _ = resolve(Animal.self) as? Cat + _ = resolve(Animal.self, argument: "Mimi") as? Cat + let lazy = resolve(Lazy.self, arguments: "Mew", true) + _ = lazy?.instance as? Cat + } + } +} diff --git a/Tests/SwinjectTests/ContainerTests.TypeForwarding.swift b/Tests/SwinjectTests/ContainerTests.TypeForwarding.swift index b6059597..426a4974 100644 --- a/Tests/SwinjectTests/ContainerTests.TypeForwarding.swift +++ b/Tests/SwinjectTests/ContainerTests.TypeForwarding.swift @@ -140,7 +140,15 @@ class ContainerTests_TypeForwarding: XCTestCase { func testContainerResolvesOptionalToNilWhenWrappedTypeIsNotRegistered() { let optionalDog = container.resolve(Dog?.self) - XCTAssertNotNil(optionalDog) + // The type of `optionalDog` is `Dog??` i.e. `Optional>` + switch optionalDog { + case .some(.none): + // Test pass + break + default: + // Any other value is incorrect + XCTFail() + } } func testContainerResolvesOptionalWithName() { @@ -152,8 +160,15 @@ class ContainerTests_TypeForwarding: XCTestCase { func testContainerResolvesOptionalToNilWithWrongName() { container.register(Dog.self, name: "Hachi") { _ in Dog() } let optionalDog = container.resolve(Dog?.self, name: "Mimi") - XCTAssertNil(optionalDog ?? nil) - XCTAssertNotNil(optionalDog) + // The type of `optionalDog` is `Dog??` i.e. `Optional>` + switch optionalDog { + case .some(.none): + // Test pass + break + default: + // Any other value is incorrect + XCTFail() + } } func testContainerResolvesOptionalWithArguments() { diff --git a/Tests/SwinjectTests/ContainerTests.swift b/Tests/SwinjectTests/ContainerTests.swift index 8e166c96..c4aa2abf 100644 --- a/Tests/SwinjectTests/ContainerTests.swift +++ b/Tests/SwinjectTests/ContainerTests.swift @@ -87,7 +87,7 @@ class ContainerTests: XCTestCase { parent.register(Cat.self) { _ in Cat() } weak var weakCat = child.resolve(Cat.self) - XCTAssertNil(weakCat) + XCTAssertNotNil(weakCat) } #if !SWIFT_PACKAGE @@ -227,7 +227,7 @@ class ContainerTests: XCTestCase { .inObjectScope(.weak) weak var cat = container.resolve(Animal.self) as? Cat - XCTAssertNil(cat) + XCTAssertNotNil(cat) } // MARK: Init completed event diff --git a/Tests/SwinjectTests/Info.plist b/Tests/SwinjectTests/Info.plist index 4f51f531..9b424a97 100644 --- a/Tests/SwinjectTests/Info.plist +++ b/Tests/SwinjectTests/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 2.8.4 + 2.10.0 CFBundleSignature ???? CFBundleVersion diff --git a/Tests/SwinjectTests/SynchronizedTests.swift b/Tests/SwinjectTests/SynchronizedTests.swift index c67ed477..b44201d9 100644 --- a/Tests/SwinjectTests/SynchronizedTests.swift +++ b/Tests/SwinjectTests/SynchronizedTests.swift @@ -70,7 +70,7 @@ class SynchronizedResolverTests: XCTestCase { func testSynchronizedResolverSynchronousReadsWrites() { let iterationCount = 3_000 - let container = Container() + let container = Container().synchronize() as! Container let registerExpectation = expectation(description: "register") let resolveExpectations = (0...self)! + return LazyChild(lazy: lazy) + } + .inObjectScope(.container) + container.register(LazyChildProtocol.self) { + let lazy = $0.resolve(Lazy.self)! + return LazyChild(lazy: lazy) + } + container.register(LazyParentProtocol.self) { + let child1 = $0.resolve(LazyChildProtocol.self)! + let singleton = $0.resolve(LazySingletonProtocol.self)! + // Previously, accessing instance here would permanently + // hijack the graph identifier to the 'recalled' state. + _ = singleton.lazy.instance + let child2 = $0.resolve(LazyChildProtocol.self)! + return LazyParent(child1: child1, child2: child2) + } + + // Resolve, but don't access lazy value yet. + _ = container.resolve(LazySingletonProtocol.self)! + + // First lazy value access in LazyParent resolve, this + // could've happened in its init or wherever. + let parent = container.resolve(LazyParentProtocol.self)! + + XCTAssertIdentical(parent.child1, parent.child2) + XCTAssertIdentical(parent.child1.lazy.instance, parent.child2.lazy.instance) + } + + func test_guaranteeThreadSafety() { + let numberOfQueues = 25 + var expectations = [XCTestExpectation]() + let resolutionDate = Date() + 1 + + struct TestModel { + let name = "Testing" + } + + let container = Container() + + for _ in 0..