Mastering Dependency Injection in iOS: Implementing a Composition Root with DI Containers in Swift

Azizbek Asadov
3 min readMay 1, 2024

The larger and more mature the application, the more it gets daunting, complex, and burdensome managing dependencies in iOS development. Therefore, many times, developers first get going with the concept of a “Composition Root” along with Dependency Injection (DI) containers. The advantages of this architectural approach are not only clean code and modular architecture but also better testability and expandability. This article intends to go in-depth into how you can actually implement a Composition Root and use DI Containers effectively in your iOS applications written using Swift.

What is a Composition Root?

The Composition Root is the exact centric location of the application where modules are composed, meaning they are instantiated and injected with all their dependencies at this spot. This means that all dependencies are configured in one single place, thereby simplifying the managing of these dependencies while following Dependency Injection.

Benefits of Using a Composition Root

  • Centralized Configuration: All dependencies are configured in one place, making the system easier to understand and modify.
  • Decoupling: Components are less dependent on each other, making them easier to test and maintain.
  • Enhanced Flexibility: Swapping out implementations or configurations can be done in one place without affecting the component’s consumers.

Dependency Injection Containers

Dependency Injection (DI) containers are frameworks that automate the process of supplying dependencies to components that require them. In iOS development, DI containers help manage object lifecycles and dependencies transparently, allowing developers to focus more on business logic rather than the boilerplate code associated with instantiating objects.

Popular iOS DI Containers

  • Swinject: A lightweight dependency injection framework for Swift.
  • Typhoon: Offers powerful dependency injection for Objective-C and Swift, though less frequently updated in recent years.
  • Dip: A simple DI container in Swift that is easy to use and understand.

Implementing a Composition Root in Swift

Let’s explore how to set up a Composition Root using Swinject, one of the most popular DI containers for Swift.

Setting Up Swinject

First, add Swinject to your project using CocoaPods, Carthage, or Swift Package Manager. For CocoaPods:

pod 'Swinject'

Configuring the Container

Create a new Swift file, CompositionRoot.swift, where you'll configure all your application's dependencies:

import Swinject

class CompositionRoot {
static let container = Container()

static func setup() {
container.register(Networking.self) { _ in NetworkService() }
container.register(Database.self) { _ in RealmDatabase() }
container.register(UserRepository.self) { r in
DefaultUserRepository(
networking: r.resolve(Networking.self)!,
database: r.resolve(Database.self)!
)
}
}

// sometimes people tend to add navigation here as well,
// yet I would rather segregate it to a separate instance
}

// I usually call it either AppCompositionRoot or a ModuleCompositionRoot. whatever

Injecting Dependencies

In your application delegate or a similar entry point, set up the DI container:

import UIKit
@_exported import Swinject // why not huh?))

@UIApplicationMain
final class AppDelegate: UIResponder, UIApplicationDelegate {

private var window: UIWindow?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
CompositionRoot.setup()

let userRepository = CompositionRoot.container.resolve(UserRepository.self)!
// utilize repos

return true
}
}

Integration with iOS Lifecycle

Integrating the Composition Root with the iOS lifecycle is crucial for maintaining clean architecture. Typically, you should set up the DI container at the very beginning of your app’s lifecycle, as shown in the AppDelegate.

Conclusion

Implementing a Composition Root with a DI container in iOS apps significantly improves the manageability and quality of your codebase. It centralizes dependency management, reduces boilerplate code, and enhances the flexibility and testability of your application. If you wanna learn more about it I’d strongly recommend watching a youtube video of one of my friends

Composition Root — The Only DI PatternSearchInfoShoppingTap to unmute2xIf playback doesn’t begin shortly, try restarting your device.•[Music]foreignUp nextLiveUpcomingCancelPlay nowShareInclude playlistAn error occurred while retrieving sharing information. Please try again later.Watch LaterShareCopy link

Or a decent and curated material by the Essential Developer

--

--