Dependency injection, in general, is beneficial for your application because it promotes loosely coupled architecture and improves testability. There are several ways of implementing dependency injection, but I believe property dependency injection is the most versatile and easy to use one. This library is an implementation of property dependency injection where you just need to declare your dependencies and use them as properties in your classes. No constructor parameters, no extra code.
For Cocoapods, add the following line to your Podfile:
pod 'PropertyInjector'For Carthage, add the following line to your Cartfile:
github "stanfeldman/PropertyInjector"You need to make sure that your dependencies get registered before they are injected. You can create a manager class and register the dependencies in its constructor.
class DependencyManager {
init() {
DependencyResolver.register {
$0.singleton(MyDependency())
// or
$0.singleton(MyInterface.self, MyImplementation())
}
}
}And add this manager to your AppDelegate for UIKit projects and App object for SwiftUI projects.
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
private let dependencyManager = DependencyManager()
}Just declare your dependency object as a property and add @Inject property wrapper. The dependency will be lazily resolved when the object is used.
class ViewController: UIViewController {
@Inject private var dependency: MyDependency
}There are 2 supported resolution strategies:
factorycreates your dependency every time it is resolvedsingletoncreates your dependency only once and reuses the instance
DependencyResolver.register {
$0.factory(MyDependency())
$0.singleton(MyDependency())
}You can register a dependency with parameters.
DependencyResolver.register {
$0.factory(MyDependency.self) { parameters in
return MyDependency(name: parameters["name"] as! String)
}
}And then resolve it using some parameters:
@Inject(with: ["name": "Boris"]) private var dependency: MyDependencyor
let sub2: SubDependency2 = DependencyResolver.resolve(with: ["name": "Boris"])Automatic property injection using @Inject is preferable, but it is possible to manually resolve a dependency.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let dependency1: MyDependency1 = DependencyResolver.resolve()
let dependency2: MyDependency2 = DependencyResolver.resolve(with: ["uuid": UUID().uuidString])
}
}Dependencies are resolved on demand so there is no problem injecting class B into class A and class A into class B as long as both dependencies are not used in their constructors.
PropertyInjector will try to resolve an unwrapped type for optionals.
class ViewController: UIViewController {
@Inject private var dependency: MyDependency? // will try to resolve as MyDependency
@Inject private var dependency: MyDependency! // the same
}To run the example project, clone the repo, and run pod install from the Example directory first.
PropertyInjector is available under the MIT license. See the LICENSE file for more info.