Last active
September 20, 2024 15:56
-
-
Save tikhonp/facd8763a16acd9018b16378e4c59c1d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // DependencyInjector.swift | |
| // | |
| // | |
| // Created by Tikhon Petrishchev on 21.02.2023. | |
| // | |
| import Foundation | |
| /// The main object where stores all references to object dependencies | |
| private struct DependencyInjector { | |
| nonisolated(unsafe) private static var dependencyList: [String: Any] = [:] | |
| private static let lock = NSRecursiveLock() | |
| static func resolve<T>() -> T { | |
| guard let object = dependencyList[String(describing: T.self)] as? T else { | |
| fatalError("No provider registered for type \(T.self)") | |
| } | |
| return object | |
| } | |
| static func resolveOptional<T>() -> T? { | |
| dependencyList[String(describing: T.self)] as? T | |
| } | |
| static func register<T>(dependency: T) { | |
| lock.withLock { | |
| dependencyList[String(describing: T.self)] = dependency | |
| } | |
| } | |
| } | |
| /// Wrapper for accessing project dependencies provided before. | |
| /// | |
| /// Note that if dependency was not provided injecting it using this wrapper will cause fatal error. | |
| /// | |
| /// Use this to inject dependency anywhere: | |
| /// | |
| /// @Inject var someObject: SomeObjectTypeOrProtocol | |
| /// | |
| @propertyWrapper public struct Inject<T> { | |
| public let wrappedValue: T | |
| public init() { | |
| self.wrappedValue = DependencyInjector.resolve() | |
| } | |
| } | |
| /// Safe wrapper for accessing dependencies that may not be provided | |
| /// | |
| /// If dependency was not provided an object will be nil | |
| /// | |
| /// Use it to inject optional dependency anywhere: | |
| /// | |
| /// @InjectOptional var someObject: SomeObjectTypeOrProtocol | |
| /// | |
| @propertyWrapper public struct InjectOptional<T> { | |
| public let wrappedValue: T? | |
| public init() { | |
| self.wrappedValue = DependencyInjector.resolveOptional() | |
| } | |
| } | |
| /// Provider wrapper for store dependencies | |
| @propertyWrapper public struct Provider<T> { | |
| public let wrappedValue: T | |
| public init(wrappedValue: T) { | |
| self.wrappedValue = wrappedValue | |
| DependencyInjector.register(dependency: wrappedValue) | |
| } | |
| } | |
| /// Inline type injecting. | |
| /// | |
| /// Quick access without defining a variable. | |
| /// ```swift | |
| /// inject(Foo.self).bar() | |
| /// ``` | |
| /// - Parameter type: Object type. | |
| /// - Returns: Resolved instance of an object | |
| public func inject<T>(_ type: T.Type) -> T { | |
| DependencyInjector.resolve() | |
| } | |
| /// Inline type injecting but return optional if not resolved. | |
| /// | |
| /// Quick access without defining a variable. | |
| /// ```swift | |
| /// injectOptional(Foo.self).bar() | |
| /// ``` | |
| /// - Parameter type: Object type. | |
| /// - Returns: Resolved instance of an object | |
| public func injectOptional<T>(_ type: T.Type) -> T? { | |
| DependencyInjector.resolveOptional() | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment