Property Injection

We have already agreed that Construction Injection is the best way to do DI, so why bother finding other methods?

Well, it is not always possible to define the constructor the way want. A notable example is doing DI with ViewControllers that are defined in storyboards. Given we have a BasketViewController that orchestrates the service and the store, we must pass them as properties:

class BasketViewController: UIViewController {
var service: BasketService?
var store: BasketStore?

// ...
}

This pattern is less elegant than the previous one:

However, something can be done:

The class BasketViewController must then be written as:

class BasketViewController: UIViewController {
private var service: BasketService!
private var store: BasketStore!

func set(service: BasketService, store: BasketStore) {
self.service = service
self.store = store
}

override func viewDidLoad() {
super.viewDidLoad()
precondition(service != nil, "BasketService required")
precondition(store != nil, "BasketStore required")
// ...
}
}

The Properties Injection permits us to have overridable properties with a default value. This can be useful in the case of testing.
Let's consider a dependency to a wrapper around the time:

class CheckoutViewController: UIViewController {
var time: Time = DefaultTime()
}

protocol Time {
func now() -> Date
}

struct DefaultTime: Time {
func now() -> Date {
return Date()
}
}

In the production code, we don't need to do anything, while in the testing code we can now inject a particular date instead of always return the current time. This would permit us of testing how the software will behave in the future, or in the past.


A dependency defined in the same module or framework is Local. When it comes from another module or framework, it's Foreign.

A Local dependency can be used as a default value, but a Foreign cannot, otherwise it would introduce a strong dependency between the modules.