Improving your Swinject routine

…with powerful extensions!

Tim Kuzmin
Feb 7 · 4 min read

If you use Swinject, I hope you already tried and enjoyed SwinjectAutoregistration as well. If not, this article is not for you. 😔

TL;DR: I made some useful extensions in the same manner as SwinjectAutoregistration to cover additional interesting cases. Just syntax sugar.

First questions

Q: First of all, why should I be enjoying using SwinjectAutoregistration?

Because it saves your time! I will cover that quickly. Imagine you have a class with some dependencies:

You can register it in your Swinject DI container in a usual way:

OR you can use autoregistration to rewrite it as a one-liner, just specify a protocol and an implementation:

Q: Ok, it can be much shorter. Is it the only benefit?

Nope! Let me show you the main advantage. Assume we need to add a dependency or remove one from our UserManager.

Fist step: remove networkService from UserManager properties and initializer:

Second step: dive into your DI-related code and delete it there too:

Good news: in autoregistration case, you don’t need second step.

Q: Nice! But what about powerful extensions you mentioned in the subtitle?

Ah, yes, here you go.

Storyboard method injection

Speaking about Dependency Injection, we can name 3 common injection patterns:

We already have it in UserManager: dependencies are passed via init.

Can be easily applied for UserManager also:

Looks like a mix of both previous: create an instance first, then inject all dependencies via some function. We will have examples below.

What about UIViewController world? While you instantiate controllers programmatically, you are free to choose any injection pattern you like. But in case of using storyboards, init door is closed.

Luckily, for other 2 ways you can use very convenient SwinjectStoryboard extension (yep, another one). It provides a completion closure to do all stuff right after your controller is resolved:

But wait, we have fallen to the problem we had with UserManager: adding serviceD requires changes in DI layer. To avoid that, there should be something like auto-initCompleted closure.

In addition, I prefer to use method injection here, not property injection. Why? To have cleaner code: to mark what is supposed to be touched by outer world, what’s not. In case of UserManager it’s supposed to use via UserManagering protocol, thus nothing around can touch its keychainService. But in ViewController example, serviceB can be accessed by child or parent controller, for instance. That’s why it’s better to set private/fileprivate (or private(set), unlikely) modifiers for serviceA/B/C and inject values via method inject:

Usually it makes sense to have more specific method name like setupViewModel.

Well, here we can start using my extensions! Simple as this:

Just write and forget about it. I just checked with git blame and made sure that ViewAssembly class content has the oldest changes across DI layer I wrote for Layette iOS app.

Feel free to run AutoStoryboardInitCompleted example!

AutoInitCompleted

As your Dependency Graph grows, you may face Circular Dependencies. Probably it comes from bad design, but sometimes it’s what we need to deal with. In this situation Swinject documentation suggests to inject each dependency (one should be stored weak, of course) in initCompleted closure. Hmm, sounds like time for another extension!

To make sure a and b will resolve, run AutoInitCompleted example. By the way, this one may be added to main SwinjectAutoregistration library, yay!

Bonus: final questions

Wow, you are still reading.

Q: Yes. You say I can pass 1/10/whatever arguments without any changes… magic outside of Hogwarts?

Actually, you can pass up to 26 arguments and I hope it’s more than enough. How does it work? Generics!

Q: Ouch, so much force unwrappings. Are you going to remove them?

Well, I’m going to add some error handling like here. For now it doesn’t hurt much: write DI stuff, try to run, it crashes on resolving, you peer on your stacktrace and fix a bug. 🧐

Q: The more params you have, the more terrifying your function looks. Are you sure you have no typos there?

Yes I am, it’s done by code generation. SwinjectAutoregistration uses it too (initially it was written in Curry) but for me it seems too long and complicated so I wrote that in less than 20 lines (for each AutoInitCompleted and AutoStoryboardInitCompleted) of Sourcery template:

That’s my first experience with Sourcery, maybe it can be templated nicer. Funny fact: if you are a code generation Jedi, you can probably do all DI work even better (many articles in Google, e.g. this).

Conclusion

That’s it! See repo playgrounds.

That’s my first article, I hope it was helpful! 👏👏👏

Many thanks to Egon Elbre for his cute tool for making gists.

Flawless iOS

🍏 Community around iOS development, mobile design, and…

Tim Kuzmin

Written by

iOS Developer

Flawless iOS

🍏 Community around iOS development, mobile design, and marketing

More From Medium

More from Flawless iOS

More from Flawless iOS

NSTimer vs CADisplayLink

More from Flawless iOS

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade