Chapter 5. Dependency Injection. - dmsl1805/Cookbook GitHub Wiki

The DI principles we use at Headway are simple:

  • implementation knows only interface
  • only Factory knows about others and other Factories

Here are some examples of how components are created:

Simple protocol just to make our code consistent

protocol StaticFactory {
    associatedtype Factory
}

Factory for TMDBApi knows how to create itself. It is also stored as static instance.

extension TMDBApi: StaticFactory {
    enum Factory {
        static let `default`: TMDBApiProvider = TMDBApi()
    }
}

Factory for MovieDetailDriver knows how inject TMDBApiProvider.

extension MovieDetailDriver: StaticFactory {
    enum Factory {
        static func `default`(id: Int) -> MovieDetailDriving {
            MovieDetailDriver(id: id, api: TMDBApi.Factory.default)
        }
    }
}

Factory for MovieDetailViewController initialises all of the components above.

extension MovieDetailViewController: StaticFactory {
    enum Factory {
        static func`default`(id: Int) -> MovieDetailViewController {
            let vc = R.storyboard.main.movieDetailViewController()!
            let driver = MovieDetailDriver.Factory.default(id: id)
            let stateBinder = MovieDetailStateBinder(viewController: vc, driver: driver)
            let actionBinder = MovieDetailActionBinder(viewController: vc, driver: driver)
            let navigationBinder = NavigationPopBinder<MovieDetailViewController>.Factory
                .pop(viewController: vc, driver: driver.didClose)
            vc.bag.insert(
                stateBinder,
                actionBinder,
                navigationBinder
            )
            return vc
        }
    }
}

Notice that there is no initialisation code inside of the components.

Also all of the components are clued to ViewController's bag, so they will be deinitialized with it.

Did you notice navigationBinder? Here is how navigation works.