Photo courtesy of www.kevinandamanda.com
Dip
is a simple Dependency Injection Container.
It's aimed to be as simple as possible yet provide rich functionality usual for DI containers on other platforms. It's inspired by .NET
's Unity Container and other DI containers.
- You start by creating
let container = DependencyContainer()
and registering your dependencies, by associating a protocol or type to afactory
. - Then you can call
container.resolve()
to resolve an instance of protocol or type using thatDependencyContainer
.
You can easily use Dip along with Storyboards and Nibs - checkout Dip-UI extensions.
Dip is completely documented and comes with a Playground that lets you try all its features and become familiar with API. You can find it in Dip.xcworkspace
.
Note: it may happen that you will need to build Dip framework before playground will be able to use it. For that select
Dip-iOS
scheme and build.
You can find bunch of usage examples in a wiki.
There are also several blog posts that describe how to use Dip and some of its implementation details:
- IoC container in Swift
- IoC container in Swift. Circular dependencies and auto-injection
- Dependency injection with Dip
File an issue if you have any question.
- Scopes. Dip supports 4 different scopes (or life cycle strategies): Prototype, ObjectGraph, Singleton, EagerSingleton;
- Named definitions. You can register different factories for the same protocol or type by registering them with tags;
- Runtime arguments. You can register factories that accept up to 6 runtime arguments;
- Circular dependencies. Dip can resolve circular dependencies;
- Auto-wiring & Auto-injection. Dip can infer your components' dependencies injected in constructor and automatically resolve them as well as dependencies injected with properties.
- Type forwarding. You can register the same factory to resolve different types.
- Storyboards integration. You can easily use Dip along with storyboards and Xibs without ever referencing container in your view controller's code;
- Weakly typed components. Dip can resolve weak types when they are unknown at compile time.
- Easy configuration. No complex container hierarchy, no unneeded functionality;
- Thread safety. Registering and resolving components is thread safe;
- Helpful error messages and configuration validation. You can validate your container configuration. If something can not be resolved at runtime Dip throws an error that completely describes the issue;
import Dip
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
// Create the container
private let container = DependencyContainer { container in
// Register some factory. ServiceImp here implements protocol Service
container.register { ServiceImp() as Service }
}
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Resolve a concrete instance. Container will instantiate new instance of ServiceImp
let service = try! container.resolve() as Service
...
}
}
import Dip
class AppDelegate: UIResponder, UIApplicationDelegate {
private let container = DependencyContainer.configure()
...
}
//CompositionRoot.swift
import Dip
import DipUI
extension DependencyContainer {
static func configure() -> DependencyContainer {
return DependencyContainer { container in
container.register(tag: "ViewController") { ViewController() }
.resolveDependencies { container, controller in
controller.animationsFactory = try container.resolve() as AnimatonsFactory
}
container.register { AuthFormBehaviourImp(apiClient: $0) as AuthFormBehaviour }
container.register { container as AnimationsFactory }
container.register { view in ShakeAnimationImp(view: view) as ShakeAnimation }
container.register { APIClient(baseURL: NSURL(string: "http://localhost:2368")!) as ApiClient }
}
}
}
extension DependencyContainer: AnimationsFactory {
func shakeAnimation(view: UIView) -> ShakeAnimation {
return try! self.resolve(withArguments: view)
}
}
extension ViewController: StoryboardInstantiatable {}
//ViewController.swift
class ViewController {
var animationsFactory: AnimationsFactory?
private let _formBehaviour = Injected<AuthFormBehaviour>()
var formBehaviour: AuthFormBehaviour? {
return _formBehaviour.value
}
...
}
Since version 4.3.1 Dip is built with Swift 2.2. The latest version built with Swift 2.1 is 4.3.0.
Dip is available through CocoaPods. To install it, simply add the following line to your Podfile:
pod "Dip"
If you use Carthage add this line to your Cartfile:
github "AliSoftware/Dip"
If you use Swift Package Manager add Dip as dependency to you Package.swift
:
let package = Package(
name: "MyPackage",
dependencies: [
.Package(url: "https://github.com/AliSoftware/Dip.git", "4.5.0")
]
)
On OSX you can run tests from Xcode. On Linux you need to have Swift Package Manager installed and use it to build and run tests:
cd Dip
swift build && swift test
Note: Swift Package Manager is destributed with Swift development snapshots only, so it builds packages using Swift 3. To build Dip you will need to build it with Swift 2.2, for that you need to set
$SWIFT_EXEC
environment variable.
This library has been created by Olivier Halligon.
I'd also like to thank Ilya Puchka for his big contribution to it, as he added a lot of great features to it.
Dip is available under the MIT license. See the LICENSE
file for more info.
The animated GIF at the top of this README.md
is from this recipe on the yummy blog of Kevin & Amanda. Go try the recipe!
The image used as the SampleApp LaunchScreen and Icon is from Matthew Hine and is under CC-by-2.0.