Skip to content

Instantly share code, notes, and snippets.

@tikhonp
Last active September 20, 2024 15:56
Show Gist options
  • Select an option

  • Save tikhonp/facd8763a16acd9018b16378e4c59c1d to your computer and use it in GitHub Desktop.

Select an option

Save tikhonp/facd8763a16acd9018b16378e4c59c1d to your computer and use it in GitHub Desktop.
//
// 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