Swiftpack.co - Package - Swinject/Swinject

Swinject

Travis CI Carthage compatible CocoaPods Version License Platforms Swift Version Reviewed by Hound

Swinject is a lightweight dependency injection framework for Swift.

Dependency injection (DI) is a software design pattern that implements Inversion of Control (IoC) for resolving dependencies. In the pattern, Swinject helps your app split into loosely-coupled components, which can be developed, tested and maintained more easily. Swinject is powered by the Swift generic type system and first class functions to define dependencies of your app simply and fluently.

Features

Extensions

Requirements

  • iOS 8.0+ / Mac OS X 10.10+ / watchOS 2.0+ / tvOS 9.0+
  • Swift 2.2 or 2.3
    • Xcode 7.0+
  • Swift 3
    • Xcode 8.0+
  • Swift 3.2, 4.x
    • Xcode 9.0+
  • Carthage 0.18+ (if you use)
  • CocoaPods 1.1.1+ (if you use)

Installation

Swinject is available through Carthage, CocoaPods, or Swift Package Manager.

Carthage

To install Swinject with Carthage, add the following line to your Cartfile.

Swift 2.2 or 2.3

github "Swinject/Swinject" ~> 1.1.4

Swift 3.x or 4.x

github "Swinject/Swinject"

# Uncomment if you use SwinjectStoryboard
# github "Swinject/SwinjectStoryboard"

Then run carthage update --no-use-binaries command or just carthage update. For details of the installation and usage of Carthage, visit its project page.

CocoaPods

To install Swinject with CocoaPods, add the following lines to your Podfile.

Swift 2.2 or 2.3

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0' # or platform :osx, '10.10' if your target is OS X.
use_frameworks!

pod 'Swinject', '~> 1.1.4'

Swift 3.x

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0' # or platform :osx, '10.10' if your target is OS X.
use_frameworks!

pod 'Swinject'

# Uncomment if you use SwinjectStoryboard
# pod 'SwinjectStoryboard'

Then run pod install command. For details of the installation and usage of CocoaPods, visit its official website.

Swift Package Manager

in Package.swift add the following:

dependencies: [
    // Dependencies declare other packages that this package depends on.
    // .package(url: /* package url */, from: "1.0.0"),
    .package(url: "https://github.com/Swinject/Swinject.git", from: "2.7.1")
],
targets: [
    .target(
        name: "MyProject",
        dependencies: [..., "Swinject"]
    )
    ...
]

Documentation

Basic Usage

First, register a service and component pair to a Container, where the component is created by the registered closure as a factory. In this example, Cat and PetOwner are component classes implementing Animal and Person service protocols, respectively.

let container = Container()
container.register(Animal.self) { _ in Cat(name: "Mimi") }
container.register(Person.self) { r in
    PetOwner(pet: r.resolve(Animal.self)!)
}

Then get an instance of a service from the container. The person is resolved to a pet owner, and playing with the cat named Mimi!

let person = container.resolve(Person.self)!
person.play() // prints "I'm playing with Mimi."

Where definitions of the protocols and classes are

protocol Animal {
    var name: String? { get }
}

class Cat: Animal {
    let name: String?

    init(name: String?) {
        self.name = name
    }
}

and

protocol Person {
    func play()
}

class PetOwner: Person {
    let pet: Animal

    init(pet: Animal) {
        self.pet = pet
    }

    func play() {
        let name = pet.name ?? "someone"
        print("I'm playing with \(name).")
    }
}

Notice that the pet of PetOwner is automatically set as the instance of Cat when Person is resolved to the instance of PetOwner. If a container already set up is given, you do not have to care what are the actual types of the services and how they are created with their dependency.

Where to Register Services

Services must be registered to a container before they are used. The typical registration approach will differ depending upon whether you are using SwinjectStoryboard or not.

The following view controller class is used in addition to the protocols and classes above in the examples below.

class PersonViewController: UIViewController {
    var person: Person?
}

With SwinjectStoryboard

Import SwinjectStoryboard at the top of your swift source file if you use Swinject v2 in Swift 3.

// Only Swinject v2 in Swift 3.
import SwinjectStoryboard

Services should be registered in an extension of SwinjectStoryboard if you use SwinjectStoryboard. Refer to the project page of SwinjectStoryboard for further details.

extension SwinjectStoryboard {
    @objc class func setup() {
        defaultContainer.register(Animal.self) { _ in Cat(name: "Mimi") }
        defaultContainer.register(Person.self) { r in
            PetOwner(pet: r.resolve(Animal.self)!)
        }
        defaultContainer.register(PersonViewController.self) { r in
            let controller = PersonViewController()
            controller.person = r.resolve(Person.self)
            return controller
        }
    }
}

Without SwinjectStoryboard

If you do not use SwinjectStoryboard to instantiate view controllers, services should be registered to a container in your application's AppDelegate. Registering before exiting application:didFinishLaunchingWithOptions: will ensure that the services are setup appropriately before they are used.

class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    let container: Container = {
        let container = Container()
        container.register(Animal.self) { _ in Cat(name: "Mimi") }
        container.register(Person.self) { r in
            PetOwner(pet: r.resolve(Animal.self)!)
        }
        container.register(PersonViewController.self) { r in
            let controller = PersonViewController()
            controller.person = r.resolve(Person.self)
            return controller
        }
        return container
    }()

    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {

        // Instantiate a window.
        let window = UIWindow(frame: UIScreen.main.bounds)
        window.makeKeyAndVisible()
        self.window = window

        // Instantiate the root view controller with dependencies injected by the container.
        window.rootViewController = container.resolve(PersonViewController.self)

        return true
    }
}

Notice that the example uses a convenience initializer taking a closure to register services to the new instance of Container.

Play in Playground!

The project contains Sample-iOS.playground to demonstrate the features of Swinject. Download or clone the project, run the playground, modify it, and play with it to learn Swinject.

To run the playground in the project, first build the project, then select Editor > Execute Playground menu in Xcode.

Example Apps

  • SwinjectSimpleExample demonstrates dependency injection and Swinject in a simple weather app that lists current weather information at some locations.
  • SwinjectMVVMExample demonstrates dependency injection with Swift and reactive programming with ReactiveCocoa in MVVM architecture.

Blog Posts

The following blog posts introduce Swinject and the concept of dependency injection.

Contribution Guide

A guide to submit issues, to ask general questions, or to open pull requests is here.

Question?

  • Slack feel free to discuss anything Swinject related.
  • Stack Overflow we are trying to monitor questions tagged swinject

Credits

The DI container features of Swinject are inspired by:

and highly inspired by:

License

MIT license. See the LICENSE file for details.

Github

link
Stars: 4265

Dependencies

Releases

v2.7.1 - 2019-09-09 09:06:29

Bugfix

  • Fixed warning when integrating Swinject via Carthage into app extension (#435). Thanks @raptorxcz!

This version supports Xcode 10.2+ with Swift 4.2+.

v2.7.0 - 2019-09-02 09:58:07

Compatibility

Swinject has been migrated do Swift 5, thus we no longer support Xcode <10.2. Projects running on Xcode 10.2+ with codebase in older Swift should not be affected.

Bugfix

  • Fixed duplicit bunde id issue in multiplatform projects (#433). Thanks @raptorxcz!

This version supports Xcode 10.2+ with Swift 4.2+.

v2.6.2 - 2019-06-21 05:58:24

Bugfix

  • Fixed swift package manager integration (#414). Thanks @thbonk!
  • Fixed premature object graph termination (#418)

This version supports Xcode 10+ with Swift 3.x / 4.2 / 5.

v2.6.1 - 2019-05-29 08:14:59

Bugfix

  • Fixed incorrect graph object scope reseting in parent container (#409).

This version supports Xcode 10+ with Swift 3.x / 4.2 / 5.

v2.6.0 - 2019-03-08 13:48:43

Compatibility

  • Added support for Xcode 10.2 & Swift 5 (#391). Thanks @tcldr!

This version supports Xcode 10+ with Swift 3.x / 4.2 / 5.

v2.5.0 - 2018-09-19 07:45:27

Compatibility

  • Added support for Xcode 10 & Swift 4.2 (#369, #371). Thanks @janhalousek, @ilijapuaca!

Documentation

  • Replaced deprecated Resolvable with Resolver (#370). Thanks @acevif!

This version supports Xcode 10 with Swift 3.x and 4.2.

v2.4.1 - 2018-06-05 15:40:02

Bugfix

  • added workaround for nested synchronized resolutions (#353, #350) Thanks @serges147, @gilroykilroy

This version supports Xcode 9+ with Swift 3.x and 4.x.

v2.4.0 - 2018-04-05 08:14:14

Compatibility

  • added compatibility with Xcode 9.3 and Swift 4.1 (#342). Thanks @Vkt0r!

This version supports Xcode 9+ with Swift 3.x and 4.x.

v2.3.0 - 2018-03-27 14:19:24

New features

  • Delayed Injection (#331, #303 ): We now have Lazy and Provider injection!
  • Type forwarding (#319): We can reuse one registration for multiple types!
  • Behaviors (#330, #322): Convenient way of adding custom steps to the registration process.

Enhanced

  • Added support for multiple initCompleted definitions (#325). Thanks @AnisovAleksey!
  • Added default scope to the assembler initialisation (#323). Thanks @libec!
  • Added support for transparently resolving the optionals of the registered types (#334).

Bugfix

  • Fixed an issue with .weak object scope in circular dependencies (#318)

Documentation

  • Brought README up to date with Swift4 (#332). Thanks @acevif!

This version supports Xcode 9+ with Swift 3.x and 4.

v2.2.0 - 2018-02-13 16:43:14

Enhanced

  • Added support for Xcode 9 (#294). Thanks @yoichitgy!
  • Added option to specify a default object scope (#291, #304). Thanks @jkaan!
  • Cleaned up hash computation (#298). Thanks @tarunon!
  • Cleaned up Swiftlint directives (#293). Thanks @knickmack!

Documentation

  • Language improvements (#307) and playground warning fixes (#306). Thanks @gemmakbarlow!

This version supports Xcode 9+ with Swift 3.x and 4.

v2.1.1 - 2017-08-14 15:48:13

Enhanced

  • Supported both Xcode 8.x and 9 beta. (#252, #262, #263, #281) Thanks @MadsBogeskov and @mackoj!
  • Cleaned up SwiftLint configurations. (#270) Thanks @jakubvano!
  • Add tests for the weak object scope. (#257) Thanks @mpdifran!
  • Remove Quick and Nimble submodules from this repository. (#259) Thanks @mpdifran!

Documentation

  • Updated CONTRIBUTING.m. (#268) Thanks @jakubvano!
  • Fixed typos. (#255) Thanks @Lutzifer!

This version supports Xcode 8.x and 9 beta with Swift 3.x and 4.

v2.1.0 - 2017-04-17 22:03:22

Fixed

  • Deprecated Assembler initializers throwing an error, and add initializers not throwing an error. (#241) Thanks @ManWithBear!
  • Fixed lint errors with SwiftLint v0.17.0. (#237) Thank @dagio!

Documentation

  • Fixed a typo. (#230) Thanks @timbroder!
  • Fixed a type mistake. (#239) Thanks @rcfrias!
  • Added a compile performance remark. (#248) By @yoichitgy.

This version supports Xcode 8.x with Swift 3.x.

v2.0.0 🎉 - 2017-01-08 11:04:30

Breaking Changes

  • Fixed typo in logingFunction property (#215). By @yoichitgy. Thanks @basalphenaar for the report!

This version supports Xcode 8.x with Swift 3.0.x.

v2.0.0-beta.3 - 2016-12-10 12:04:53

Breaking Changes

  • Renamed protocols for Swift 3 API conformance (#157, #203). By @jakubvano and @yoichitgy
  • Changed Assembler to final class (#193). By @yoichitgy
  • Removed .container object scope, and renamed .hierarchy scope to new .container scope (#165). By @jakubvano

Enhanced

  • Made object scopes customizable (#165). By @jakubvano
  • Added .weak object scope (#198). By @jakubvano
  • Added logging of resolution failure (#160). By @jakubvano
  • Updated support of Swift Package Manager and Linux with Swift 3 (#196, #202). By @yoichitgy and @jakubvano

Fixed

  • Added @escaping to the factory closure of register method (#194, #195). Thanks @kdubb!

Documentation

  • Updated playground for Swift 3 (#167). By @jakubvano

This version supports Xcode 8.1 with Swift 3.0.1.

v1.1.5 - 2016-10-11 12:10:24

Fixed

  • Reverted postponing initCompleted calls (#164) which was causing some issues (#158, #159). A workaround for the original issue #133 is documented. Thanks @marcorei for collaboration!

Enhanced

  • Added logging of resolution failure (#168) which should help with debugging. By @jakubvano.

This version supports Xcode 7.3 with Swift 2.2 and Xcode 8 with Swift 2.3.

v2.0.0-beta.2 - 2016-09-11 08:52:29

Breaking Changes

  • Supported Swift 3 (#113). Thanks @garnett!

Fixed

  • Fixed Package.swift to Swift Package Manager (#123)

Documentation

  • Fixed typos (#120). Thanks @ybodson!
  • Fixed incorrect description about method injection (#142). Thanks @mpdifran!

This version supports Xcode 8 (GM) with Swift 3.

v1.1.4 - 2016-09-10 16:59:16

Fixed

  • Dependencies of ViewControllers are getting injected multiple times using reference Storyboards. (#125, #144) Thanks @jakubvano!
  • Dependencies of non-root UIViewControllers are not getting storyboard injected. (#128, #144) Thanks @jakubvano!
  • Updated the project settings as recommended by Xcode 8 (GM). (#145)

This version supports Xcode 7.3 with Swift 2.2 and Xcode 8 (GM) with Swift 2.3.

v1.1.3 - 2016-08-29 03:55:09

Fixed

  • Extra instantiation of instances with circular dependency even in .Container scope. (#133, #134) Thanks @marcorei!

Enhanced

  • Added SWIFT_VERSION = 2.3 to support both Xcode 7 and 8 (beta) in Swift 2. (#129) Thanks @thalmicMark!

Internally enhanced

  • Replaced respondsToSelector call with optional chaining. (#109) Thanks @amccarri!

This version supports Xcode 7.3 with Swift 2.2 and Xcode 8 (beta) with Swift 2.3.

v2.0.0-beta.1 - 2016-07-01 17:01:31

Breaking Changes

  • Changed the API to resolve a service with multiple arguments (#63, #118). Thanks @jakubvano!
  • Moved SwinjectStoryboard to its own repository (#92). Specify it in your Cartfile or Podfile if you use it.
  • Moved SwinjectPropertyLoader to its own repository (#93). Specify it in your Cartfile or Podfile if you use it.
  • Renamed Resolvable to ResolverType protocol, and removed previous ResolverType typealias. (#90, #87).

Enhanced

  • Replaced OSSpinLock with NSLock for safety against thread priority (#116). Thanks @noremac!
  • Replaced respondsToSelector call with optional chaining (#109). Thanks @amccarri!
  • Added CustomStringConvertible conformance to Container (#65, #66)

The framework targets Swift 2.2 / Xcode 7.3.

v1.1.2 - 2016-05-16 14:34:45

Fixed

  • Warnings for selectors with Swift 2.2 compiler (#101).

Thanks @jlyonsmith for enhancing the documentation (#86) and updating dependencies in Cartfile (#85).

The prebuilt framework targets Swift 2.2 / Xcode 7.3. If you use another version of Xcode with Carthage, you might need to run carthage update command with --no-use-binaries option.

v1.1.1 - 2016-03-23 23:11:55

Added

  • Support of Xcode 7.3 / Swift 2.2 (#73, #75).

Fixed

  • Carthage build error in some cases if a new version of SwiftLint is installed (#74).

The prebuilt framework targets Swift 2.2 / Xcode 7.3. If you use another version of Xcode with Carthage, you might need to run carthage update command with --no-use-binaries option.

v1.1.0 - 2016-02-06 06:05:41

Added

  • Assembly hierarchy (#50, #58). Thanks @Nikita2k, and @mowens for review!

Fixed

  • Error on carthage build where a later version of SwiftLint is installed (#61, #60).

Also, thanks @antonmes for improvement to README.

The prebuilt framework targets Swift 2.1.1 / Xcode 7.2.x. If you use another version of Xcode with Carthage, you might need to run carthage update command with --no-use-binaries option.

v1.0.0 - 2015-12-21 16:49:01

The first stable release 🎉

No changes from v1.0.0 beta 3. Thanks @mowens for adding cool features, and everyone for submitting issues or using Swinject!

The prebuilt framework targets Swift 2.1.1 / Xcode 7.2. If you use another version of Xcode with Carthage, you might need to run carthage update command with --no-use-binaries option.

v1.0.0-beta.3 - 2015-12-12 06:03:46

Added

Breaking Change

  • Reduced the number of arguments on overloads of register and resolve methods to 9 (#38, #42)

The prebuilt framework targets Swift 2.1.1 / Xcode 7.2. If you use another version of Xcode with Carthage, you might need to run carthage update command with --no-use-binaries option.

v1.0.0-beta.2 - 2015-12-09 10:42:44

Added

Enhanced

  • Replaced ServiceEntryBase with ServiceEntryType typealias to remove unnecessary inheritance of ServiceEntry type (#33)
  • Changed the accessibility of Box<T> class from public to internal to avoid conflict with types defined in the other frameworks or user's app.

The prebuilt framework targets Swift 2.1.1 / Xcode 7.2. If you use another version of Xcode with Carthage, you might need to run carthage update command with --no-use-binaries option.

v1.0.0-beta.1 - 2015-11-27 09:50:10

This release targets Swift 2.1 / Xcode 7.1.

Added

  • Thread safety: synchronize method on a container returns a thread safe view of the container. #29

Enhanced

  • Removed usage of NSException to get rid of Objective-C dependency.

Breaking change

  • Changed the signatures of resolve methods with registration name and arguments from resolve(_:arguments:name:) to resolve(_:name:arguments:) and from resolve(_:argument:name:) to resolve(_:name:argument:) for consistency with register methods. #30

v0.5 - 2015-11-09 14:45:10

This release targets Swift 2.1 / Xcode 7.1.

Breaking change

  • resolve method taking arguments got new method signatures. Use resolve(_:argument:) or resolve(_:arguments:) methods to pass arguments (#24).

v0.4.1 fixed a tvOS issue - 2015-11-02 11:07:04

This release targets Swift 2.1 / Xcode 7.1.

Fixed

  • Dependency injection to a subclass of AVPlayerViewController instantiated from a storyboard fails in case of tvOS (Issue #18).

v0.4 supporting tvOS - 2015-10-27 13:49:18

This release targets Swift 2.1 / Xcode 7.1.

Added

  • tvOS support.
  • Convenience initializer taking a closure to register services.

Known Issue

  • Dependency injection to a subclass of AVPlayerViewController instantiated from a storyboard fails in case of tvOS (Issue #18).

v0.3 with storyboard enhancement - 2015-10-12 10:58:46

This release targets Swift 2.0 / Xcode 7.0.

Added

  • Support of implicit instantiation of UIWindow and its root view controller from "Main" storyboard.
  • Support of Storyboard References.

See the documentation for their details.

Removed

  • Static property Container.defaultContainer.