From 2f57d0ab1da74be49383c71f9875f823e110ceab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20Coye=20de=20Brune=CC=81lis?= Date: Tue, 21 Jan 2025 09:27:18 +0100 Subject: [PATCH 1/3] fix(InjectService): Property wrapper is now sendable --- Sources/InfomaniakDI/InjectService.swift | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Sources/InfomaniakDI/InjectService.swift b/Sources/InfomaniakDI/InjectService.swift index da6a4d7..c4f5cf9 100644 --- a/Sources/InfomaniakDI/InjectService.swift +++ b/Sources/InfomaniakDI/InjectService.swift @@ -16,7 +16,7 @@ import Foundation // MARK: - InjectService /// A property wrapper that resolves shared objects when the host type is initialized. -@propertyWrapper public struct InjectService: CustomDebugStringConvertible, Equatable, Identifiable { +@propertyWrapper public struct InjectService: CustomDebugStringConvertible, Equatable, Identifiable, Sendable { /// Identifiable /// /// Something to link the identity of this property wrapper to the underlying Service type. @@ -40,15 +40,14 @@ import Foundation """ } - /// Store the resolved service - var service: Service! + let service: Service - public var container: SimpleResolvable - public var customTypeIdentifier: String? - public var factoryParameters: [String: Any]? + public let container: SimpleResolvable + public let customTypeIdentifier: String? + public let factoryParameters: [String: Sendable]? public init(customTypeIdentifier: String? = nil, - factoryParameters: [String: Any]? = nil, + factoryParameters: [String: Sendable]? = nil, container: SimpleResolvable = SimpleResolver.sharedResolver) { self.customTypeIdentifier = customTypeIdentifier self.factoryParameters = factoryParameters From a0e0217414e83136e60c106900b0c4d00c8db014 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20Coye=20de=20Brune=CC=81lis?= Date: Tue, 21 Jan 2025 10:19:53 +0100 Subject: [PATCH 2/3] fix(LazyInjectService): Property wrapper is now sendable --- Sources/InfomaniakDI/LazyInjectService.swift | 31 ++++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/Sources/InfomaniakDI/LazyInjectService.swift b/Sources/InfomaniakDI/LazyInjectService.swift index 0ca695d..46e3be3 100644 --- a/Sources/InfomaniakDI/LazyInjectService.swift +++ b/Sources/InfomaniakDI/LazyInjectService.swift @@ -14,7 +14,11 @@ import Foundation /// Inject a service at the first use of the property -@propertyWrapper public final class LazyInjectService: Equatable, Identifiable { +@propertyWrapper public final class LazyInjectService: Equatable, Identifiable, @unchecked Sendable { + private let semaphore = DispatchSemaphore(value: 1) + + var service: Service? + /// Identifiable /// /// Something to link the identity of this property wrapper to the underlying Service type. @@ -38,15 +42,12 @@ import Foundation """ } - /// Store the resolved service - var service: Service? - - public var container: SimpleResolvable - public var customTypeIdentifier: String? - public var factoryParameters: [String: Any]? + public let container: SimpleResolvable + public let customTypeIdentifier: String? + public let factoryParameters: [String: Sendable]? public init(customTypeIdentifier: String? = nil, - factoryParameters: [String: Any]? = nil, + factoryParameters: [String: Sendable]? = nil, container: SimpleResolvable = SimpleResolver.sharedResolver) { self.customTypeIdentifier = customTypeIdentifier self.factoryParameters = factoryParameters @@ -55,16 +56,20 @@ import Foundation public var wrappedValue: Service { get { + semaphore.wait() + defer { semaphore.signal() } + if let service { return service } do { - service = try container.resolve(type: Service.self, - forCustomTypeIdentifier: customTypeIdentifier, - factoryParameters: factoryParameters, - resolver: container) - return service! + let resolvedService = try container.resolve(type: Service.self, + forCustomTypeIdentifier: customTypeIdentifier, + factoryParameters: factoryParameters, + resolver: container) + service = resolvedService + return resolvedService } catch { fatalError("DI fatal error :\(error)") } From ef0650d1c677455667988d570c4b53e6eae5f3f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20Coye=20de=20Brune=CC=81lis?= Date: Tue, 21 Jan 2025 14:56:01 +0100 Subject: [PATCH 3/3] refactor: Keep a swift 5.x approch for compatibility's sake --- Sources/InfomaniakDI/InjectService.swift | 7 ++++--- Sources/InfomaniakDI/LazyInjectService.swift | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Sources/InfomaniakDI/InjectService.swift b/Sources/InfomaniakDI/InjectService.swift index c4f5cf9..423d58b 100644 --- a/Sources/InfomaniakDI/InjectService.swift +++ b/Sources/InfomaniakDI/InjectService.swift @@ -16,7 +16,8 @@ import Foundation // MARK: - InjectService /// A property wrapper that resolves shared objects when the host type is initialized. -@propertyWrapper public struct InjectService: CustomDebugStringConvertible, Equatable, Identifiable, Sendable { +@propertyWrapper public struct InjectService: CustomDebugStringConvertible, Equatable, Identifiable, + @unchecked Sendable { /// Identifiable /// /// Something to link the identity of this property wrapper to the underlying Service type. @@ -44,10 +45,10 @@ import Foundation public let container: SimpleResolvable public let customTypeIdentifier: String? - public let factoryParameters: [String: Sendable]? + public let factoryParameters: [String: Any]? public init(customTypeIdentifier: String? = nil, - factoryParameters: [String: Sendable]? = nil, + factoryParameters: [String: Any]? = nil, container: SimpleResolvable = SimpleResolver.sharedResolver) { self.customTypeIdentifier = customTypeIdentifier self.factoryParameters = factoryParameters diff --git a/Sources/InfomaniakDI/LazyInjectService.swift b/Sources/InfomaniakDI/LazyInjectService.swift index 46e3be3..4457ace 100644 --- a/Sources/InfomaniakDI/LazyInjectService.swift +++ b/Sources/InfomaniakDI/LazyInjectService.swift @@ -14,7 +14,7 @@ import Foundation /// Inject a service at the first use of the property -@propertyWrapper public final class LazyInjectService: Equatable, Identifiable, @unchecked Sendable { +@propertyWrapper public final class LazyInjectService: Equatable, Identifiable, @unchecked Sendable { private let semaphore = DispatchSemaphore(value: 1) var service: Service? @@ -44,10 +44,10 @@ import Foundation public let container: SimpleResolvable public let customTypeIdentifier: String? - public let factoryParameters: [String: Sendable]? + public let factoryParameters: [String: Any]? public init(customTypeIdentifier: String? = nil, - factoryParameters: [String: Sendable]? = nil, + factoryParameters: [String: Any]? = nil, container: SimpleResolvable = SimpleResolver.sharedResolver) { self.customTypeIdentifier = customTypeIdentifier self.factoryParameters = factoryParameters