Dependency Injection and Networking in iOS


#1

Hi Ben, thanks once again for producing such high quality content. I’ve benefited a lot from your tutorials, and hope that you continue to keep up the good work!

I have a question for you about Dependency Injection and Networking in iOS:

If I have multiple View Controllers in my app which require network functionality. For example, I have one call to URLSession which pulls a generic list of data to populate a UITableView, and the next ViewController needs to make ANOTHER network call to a different API in order to pull more specific data from a REST API in order to populate that Details screen. Should I use Dependency Injection, and technically have multiple instances of my URLSession class to connect to different API, or do I use a Singleton (which I would like to avoid), and use a single reference from my Networking layer in order to call multiple API’s? What is the best approach between these two options, and is there a third option which is even better which I’m overlooking? Just wondering.

Thanks once again Ben for your time!

Take care.


#2

I like to conceptualize access to a single API as a an object, so in this case you’d have 2 classes:

FooApiClient and BarApiClient

You can often make the case that sharing access to instances of these makes sense, for instance, to keep track of long running tasks (such as downloads) or to cancel requests that are no longer needed. In this case you have to have a static sharedInstance that you use from everywhere, or use DI to pass it in.

If you don’t have either of these needs, then you can probably just instantiate the clients directly in the view controllers.

The advantage you’d get by using dependency injection (combined with an extracted protocol that describes the object’s role) then you can be more flexible about what you pass in. The best use case for this is testing. You can instantiate a view controller with a dummy implementation of the protocol and the view controller doesn’t know or care.

Dependency Injection on iOS can get tedious, especially if you’re using Storyboards. Typically you have to pass along dependencies in prepareForSegue, so your view controllers need to do a little extra work for the destination view controller to be ready.

This tradeoff is usually worth it in my opinion, though lately I’ve been leaning on Coordinators that make handling view controller dependencies a bit more structured.


#3

That all sounds like good, sensible advice, and I wanted to add a little about using prepareForSegue to provide API client objects (or the like) to a view controller. As you say, it can be pretty tedious to use DI in iOS, and especially when using Swift, it forces you to declare the injected properties as either optional types, or to provide default values upon instantiation. In either case you must also declare them as var properties to allow them to be set by an external actor, which loses the benefits of immutability.

All that to say, this works, but has some caveats.

I’m curious to hear more about Coordinators, though. Do you have any links to describe what you’re talking about in more detail?


#4

I cover this a little it in this series: https://nsscreencast.com/series/7-refactoring-to-coordinators

Basically Coordinators take the place of your segues, so you instead call a method on your coordinator to indicate user intent. photoSelected(...) for instance.

Then the coordinator builds up & presents the next view controller in the flow.

If you have 2 view controllers A and B, and B has a couple dependencies, it means that A doesn’t need to carry these along just so it can create B (this responsibility is moved up to the coordinator).

This is extra painful if you have a view controller C with an unrelated dependency, so you end up passing it along like this A -> B -> C. With coordinator it will hold the dependencies for the things it needs to create, and each view controller can stay focused on just its content/actions.