Last active
September 4, 2022 10:56
-
-
Save IuriiIaremenko/7a3b8655e8f426adb0778b480c33e5f1 to your computer and use it in GitHub Desktop.
Swift Dependency Injection via Property Wrapper
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
// | |
// Inject.swift | |
// | |
// Created by Iurii Iaremenko on 11.01.2020. | |
// | |
import Foundation | |
@propertyWrapper | |
public class Inject<Value> { | |
private let name: String? | |
private var storage: Value? | |
public var wrappedValue: Value { | |
storage ?? { | |
let value: Value = Dependencies.root.resolve(for: name) | |
storage = value | |
return value | |
}() | |
} | |
public init() { | |
self.name = nil | |
} | |
public init(_ name: String) { | |
self.name = name | |
} | |
} | |
final class Dependencies { | |
static let root = Dependencies() | |
private var factories = [String: () -> Any]() | |
private var inited = [Any]() | |
private init() { | |
setupDependencies() | |
} | |
func add<T>(_ factory: @autoclosure @escaping () -> T) { | |
let key = String(describing: T.self) | |
factories[key] = factory | |
} | |
func resolve<T>(for name: String? = nil) -> T { | |
if let component: T = inited.first(where: { $0 is T }) as? T { | |
return component | |
} | |
let name = name ?? String(describing: T.self) | |
guard let component: T = factories[name]?() as? T else { | |
fatalError("Dependency '\(T.self)' not resolved!") | |
} | |
inited.append(component) | |
return component | |
} | |
} | |
extension Dependencies { | |
/// Important: all dependencies must be registered here | |
func setupDependencies() { | |
add(Service()) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment