Swift - Dependency Injection for View Controllers

I am starting to write code in Swift and thinking about how to do things and make best use of some of its features.

One thing I am always having to do is to inject dependencies into view controllers when they are being setup. In Objective-C I will generally be doing this in prepareForSegue:sender:, something like:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:Segue_Details]) {
        DetailViewsController *vc = segue.destinationViewController;
        Details *details = ...;
        vc.details = details;
    }
}

The Details object is really required in order that the DetailsViewController works properly.

So how do we set stuff up in Swift?

The Details are not available when the DetailsViewController is being initialised from the Storyboard. So it needs to be set up as an Optional so that it can be set later,

var details: Details?

But then every time you use the Optional you have to check and force unwrap. I would prefer that if the value is not set that we fail as early as possible to make debugging problems easier. I also want to avoid having to force unwrap optional values every time I access them.

So this is how I am doing it...

Define the var as an Implicitly Unwrapped Optional

var details: Details!

This means that we do not have to explicitly force unwrap it every time we access it because we are guaranteeing that it will be set before we start accessing it. However, if it is not set we are going to get into problems at runtime because the unwrapping still happens and will fail. So how do we guarantee that the value is set?

We want to fail as early as possible if it is not set so in func viewDidLoad() we add an assert,

assert(details != nil, "details should be set")

And in addition to this we want to fail as early as possible if someone tries to set the value back to nil. So we can refine the original property declaration to

var details: Details! {
    willSet(newDetails) {
        assert(newDetails != nil, "newDetails is required")
    }
}

This is a first foray into Swift and so I am learning as I go along. If anyone has come up with other ways to do this I would love hear how you are tackling things. Get in touch with me using Twitter (@StevenOglesby) or using the form below.

About Dr Steven Oglesby

Steven leads the technical team at the The Boffin Lab.

He has 20 years experience in the software industry, haven taken the lead developer role a number of large financial systems.  Prior to his software career he achieved a PhD in Particle Physics working on the Large Hadron Collider at CERN.

Steven's our lead developer and is happiest coming up with simple solutions to the hardest technical problems.  Like all the team he wants to make the best products he can so he's always looking for innovations that can push us forward.

Outside work Steven is runner, currently chasing a new marathon PB when he's not chasing after his family.

Find him online

   

Dr Steven Oglesby