Swiftpack.co - Package - AliSoftware/Dip

Dip

CI Status Version Carthage Compatible License Platform Swift Version Swift Version

Animated Dipping GIF
Photo courtesy of www.kevinandamanda.com

Introduction

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 a factory using container.register { MyService() as Service }.
  • Then you can call container.resolve() as Service to resolve an instance of protocol or type using that DependencyContainer.
  • You can easily use Dip along with Storyboards and Nibs . There is also a code generator that can help to simplify registering new components.
Basic usage
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
    
        ...
    }
}

More sophisticated example
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 
			unowned let container = container
			DependencyContainer.uiContainers = [container]
		
			container.register(tag: "ViewController") { ViewController() }
			  .resolvingProperties { 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
    }
	...
}

Documentation & Usage Examples

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 scheme and build for iPhone Simulator.

You can find bunch of usage examples and usfull tips in a wiki.

If your are using VIPER architecture - here is VIPER demo app that uses Dip instead of manual dependency injection.

There are also several blog posts that describe how to use Dip and some of its implementation details:

File an issue if you have any question. Pull requests are warmly welcome too.

Features

  • Scopes. Dip supports 5 different scopes (or life cycle strategies): Unique, Shared, Singleton, EagerSingleton, WeakSingleton;
  • Auto-wiring & Auto-injection. Dip can infer your components' dependencies injected in constructor and automatically resolve them as well as dependencies injected with properties.
  • Resolving optionals. Dip is able to resolve constructor or property dependencies defined as optionals.
  • Type forwarding. You can register the same factory to resolve different types implemeted by a single class.
  • Circular dependencies. Dip will be able to resolve circular dependencies if you will follow some simple rules;
  • Storyboards integration. You can easily use Dip along with storyboards and Xibs without ever referencing container in your view controller's code;
  • 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 (and extend it if you need);
  • Easy configuration & Code generation. No complex containers hierarchy, no unneeded functionality. Tired of writing all registrations by hand? There is a cool code generator that will create them for you. The only thing you need is to annotate your code with some comments.
  • Weakly typed components. Dip can resolve "weak" types when they are unknown at compile time.
  • 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;

Installation

You can install Dip using your favorite dependency manager:

CocoaPods

pod "Dip"

Carthage
github "AliSoftware/Dip"

To build for Swift 2.3 run Carthage with --toolchain com.apple.dt.toolchain.Swift_2_3 option.

Swift Package Manager
.Package(url: "https://github.com/AliSoftware/Dip", majorVersion: 5, minor: 0)

Running tests

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 using this command: swift build --clean && swift build && swift test

Credits

This library has been created by Olivier Halligon and is maintained by Ilya Puchka.

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.

Github

link
Stars: 832

Dependencies

Used By

Total: 0

Releases

7.1.1 - 2019-12-27 11:38:13

  • Fixed using StoryboardInstantiatable with SPM (#233).

- 2019-11-10 16:12:35

  • You can now use a shorthand syntax for resolving a single property using a key path, i.e. resolvingProperty(\.value).
  • Swift 5.0 support (#224).
  • Fixed resolving nested types with the same local names (#221).
  • @Injected and @IntectedWeak property wrappers (#225).
  • Thread safety can be disabled on container level.

- 2018-12-20 01:24:03

  • Added a workaround for Swift 4.2 regression related to retaining weak properties (#214). For that auto-injection can be disabled or enabled for the whole container or individula registrations.

Swift 4.2 - 2018-09-22 20:37:59

  • Swift 4.2 support.
  • Fixed some issues when reusing instances previously resolved as optionals.
  • Dip-UI is now part of Dip.

Swift 4 - 2018-09-22 20:32:22

  • Swift 4 support
  • Fixed unneeded reuse of singletons in collaborating containers. Containers now first attempt to autowire components and fallback to collaboration when it fails. #169, @ilyapuchka

Swift 3.1 and some bug fixes - 2017-04-09 11:38:20

Fixed

Swift 2.3 compatibility fix - 2016-11-01 16:10:24

Fixed

  • Fixed broken compatibility for Swift 2.3 API in resolve(tag:arguments:) method. #135, @ilyapuchka

Swift 2.3 compatibility - 2016-10-23 20:57:57

  • Added Swift 2.3 compatibility. swift2.3 brunch is no longer maintained.
    #127, @ilyapuchka

Fixed

  • Fixed reusing instances registered with WeakSingleton scope
    #129, @ilyapuchka

Swift 3 reflection issues fixed - 2016-10-09 09:49:21

Fixed

CocoaPods fix - 2016-09-16 10:29:13

This release is the same as 5.0.0 and only fixes CocoaPods speck pushed to trunk without macOS, tvOS and watchOS deployment targets. Please use this release instead of 5.0.0 if you integrate Dip via Cocoapods.

Swift 3 - 2016-09-11 20:11:58

New

  • Migrated to Swift 3.0
    #120, @patrick-lind, @mark-urbanthings, @ilyapuchka
  • Renamed DefinitionOf to Definition and some other source-breaking refactoring.
    #113, @ilyapuchka
  • Added invalidType error when resolved instance does not implement requested type.
    #118, @ilyapuchka
  • Added optional type parameter in register methods to be able to specify type when registering using method literal instead of closure. #115, @ilyapuchka
  • Added implements family of methods in to Definition to register type-forwarding definitions.
    #114, @ilyapuchka
  • Shared scope is now the default scope.
    #112, @ilyapuchka
  • Single target project setup.
    #121, @ilyapuchka
  • Simplified implementation of auto-wiring. Container now chooses the definition for type with most number of arguments and does not use other definitions if this one fails to resolve. #117, @ilyapuchka

Fixed

  • Auto-injected properties inherited from super class are now properly injected when resolving subclass. Added resolveDependencies(_:DependencyContainer) method to Resolvable protocol to handle inheritance when resolving.
    #116, @ilyapuchka

- 2016-08-14 21:25:06

New

Fixed

  • Fixed sharing singletons between collaborating containers #103, @ilyapuchka

Notes on API changes

All changes are made by adding new API and deprecating old versions. They will be removed in the next release.

  1. ObjectGraph scope is renamed to Shared, Prototype scope is renamed to Unique.
  2. resolveDependencies method of DefinitionOf<T> is renamed to resolvingProperties
  3. DefinitionKey properties protocolType is renamed to type, associatedTag is renamed to tag, argumentsType is renamed to typeOfArguments.
  4. resolve method parameter withArguments is renamed to arguments. That change affects all resolve methods of DependencyContainer
  5. Order of scope and tag parameters in register method is switched. That change affects all register methods of DependencyContainer

Containers collaboration & weak singletons - 2016-07-17 20:16:01

New features

  • Containers collaboration. Break your definitions in modules and link them together.
    #95, @ilyapuchka
  • Added WeakSingleton scope.
    #96, @ilyapuchka
  • Properties auto-injection now is performed before calling resolveDependencies block
    #97, @ilyapuchka
  • Fixed updating container's context when resolving properties with auto-injection.
    #98, @ilyapuchka
  • Improved logging.
    #94, #99, @ilyapuchka
  • Fixed warning about using only extensions api.
    #92, @mwoollard

Type forwarding, weak types & optionals - 2016-06-08 21:48:20

New features

  • Added weakly-typed API to resolve components when exact type is unknown during compile time.
    #79, @ilyapuchka
  • Added type forwarding feature. You can register the same factory to resolve different types.
    #89, @ilyapuchka
  • Container now can resolve optional types :tada:
    #84, @ilyapuchka
  • Added container context that provides contextual information during graph resolution process.
    #83, @ilyapuchka
  • Added method to validate container configuration.
    #87, @ilyapuchka
  • Added method to manually set value wrapped by auto-injection wrappers.
    #81, @ilyapuchka
  • Added separate error type for failures during auto-wiring.
    #85, @ilyapuchka

Note

With introduction of type-forwarding the behavior of func resolveDependencies(block: (DependencyContainer, T) throws -> ()) -> DefinitionOf<T, F> changed. Now you can call this method several times on the same definition. When instance is resolved using this definition the container will call all the blocks that you passed to this method in the same order as you called this method.

Eager Singletons - 2016-03-31 21:08:48

New features

  • Added .EagerSingleton scope for objectes requiring early instantiation and bootstrap() method on DepenencyContainer. Call bootstrap to fix container setup and instantiate all eager singletons.
    #65, @ilyapuchka

Bug fixes

  • Reverted order of Resolvable callbacks. Now last resolved Resolvable instance will receive didResolveDependencies callback first.
    #67, @ilyapuchka

Swift 2.2 - 2016-03-24 11:28:12

Fixed

Auto-wiring, Resolvable & DependencyTagConvertible - 2016-03-19 16:55:02

New features

  • Added DependencyTagConvertible protocol for better typed tags.
    #50, @gavrix
  • Auto-wiring. DependencyContainer resolves constructor arguments automatically.
    #55, @ilyapuchka
  • Added Resolvable protocol to get a callback when dependencies graph is complete.
    #57, @ilyapuchka
  • Removed DipError.ResolutionFailed error for better consistency.
    #58, @ilyapuchka

SMP & Linux - 2016-03-19 15:58:02

New features

Bug fixes

  • Fixed the issue that could cause singleton instances to be reused between different containers.
    #43, @ilyapuchka

Auto-Injection, Errors handling & Thread-Safety - 2016-02-04 20:08:30

New features

  • Added auto-injection feature.
    #13, @ilyapuchka
  • Factories and resolveDependencies blocks of DefinitionOf are now allowed to throw. Improved errors handling. #32, @ilyapuchka
  • Thread safety reimplemented with support for recursive methods calls.
    #31, @mwoollard

- 2015-12-12 21:37:12

New

  • Added name for the first runtime argument in resolve(tag:withArguments: … ) methods to make more clear separation between tag and factory runtime arguments.

Depreciations

  • resolve(tag:_: … ) methods are deprecated in favor of those new resolve(tag:withArguments: … ) methods.
  • Deprecated register(tag:instance:) method in favor of register(.Singleton) { … }.

Circular Dependencies & throw - 2015-12-12 21:36:18

New Features

  • Added support for circular dependencies:
    • Added ObjectGraph scope to reuse resolved instances
    • Added resolveDependencies method on DefinitionOf class to resolve dependencies of resolved instance.
      #11, @ilyapuchka
  • Added methods to register/remove individual definitions.
    #11, @ilyapuchka
  • All resolve methods now can throw error if type can not be resolved.
    #15, @ilyapuchka
  • DependencyContainer is marked as final.
  • Added support for OSX, tvOS and watchOS2.
    #26, @ilyapuchka

Breaking Changes

  • Removed container thread-safety to enable recursion calls to resolve.
    Access to container from multiple threads should be handled by clients from now on.

  • All resolve methods now can throw.

    Note on migration from 3.x to 4.0.0:

    • Errors

    In 4.0.0 each resolve method can throw DefinitionNotFound(DefinitionKey) error, so you need to call it using try! or try?, or catch the error if it's appropriate for your case. See #15 for rationale of this change.

    • Thread safety

    In 4.0.0 DependencyContainer drops any guarantee of thread safety. From now on code that uses Dip must ensure that it's methods are called from a single thread. For example if you have registered type as a singleton and later two threads try to resolve it at the same time you can have two different instances of type instead of one as expected. This change was required to enable recursive calls of resolve method to resolve circular dependencies.

    • Removed methods

    Methods deprecated in 3.1.0 are now removed.

- 2015-11-22 13:41:50

  • Improved README
  • Imrpoved discoverability using keywords in podspec

- 2015-11-22 13:41:40

Dip

  • Added Unit Tests for SWAPIPersonProvider and SWAPIStarshipProvider

All work in progress is now done. I consider Dip to be ready for production and with a stable API, hence the 1.0.0 version bump.

Example Project

  • Using func fetchIDs and func fetchOne instead of lazy var for readability

- 2015-11-22 13:41:22

Dip

  • Dip is now Thread-Safe
  • Added a configuration block so we can easily create the container and register the dependencies all in one expression:
let deps = DependencyContainer() {
  $0.register() { x as Foo }
  $0.register() { y as Bar }
  $0.register() { z as Baz }
}
  • Source Documentation

Example Project

  • Code Cleanup
  • Added more values to HardCodedStarshipProvider so it works when the PersonProviderAPI uses real pilots from swapi.co (SWAPIPersonProvider)

- 2015-11-22 13:41:04

Example Project

  • Added SWAPIPersonProvider & SWAPIStarshipProvider that use http://swapi.co

- 2015-11-22 13:40:46

Example Project

  • Revamped the Sample project to a more complete example (using StarWars API!)
  • Using Mixins & Traits in the Sample App for FetchableTrait and FillableCell

- 2015-11-22 13:40:36

Dip

  • Switched from class methods to instance methods (#1). This allows you to have multiple DependencyContainers
  • Renamed the class from Dependency to DependencyContainer
  • Renamed the instanceFactory: parameter to factory:
  • Made the DependencyContainer generic of the type of tag. We are no longer limited to tags of type String, we can now use anything that's Equatable.

Initial version - 2015-11-22 13:40:07

Initial version to release the early proof of concept.

Ready to use, but API may change, documentation and unit tests are missing, and thread-safety is not guaranteed.

- 2015-11-22 13:36:08

  • Added support for factories with up to six runtime arguments.
    #8, @ilyapuchka
  • Parameter tag is now named in all register/resolve methods.
  • Playground added to project.
    #10, @ilyapuchka

- 2015-11-22 13:35:59

  • Moved from generic tag parameter on container to Tag enum with String and Int cases
    #3, @ilyapuchka

This API change allows easier use of DependencyContainer and avoid some constraints. For a complete rationale on that change, see PR #3.