TL;DR: I made some useful extensions in the same manner as SwinjectAutoregistration to cover additional interesting cases. Just syntax sugar.
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
Fist step: remove
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
Can be easily applied for
Looks like a mix of both previous: create an instance first, then inject all dependencies via some function. We will have examples below.
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
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
serviceB can be accessed by child or parent controller, for instance. That’s why it’s better to set
private(set), unlikely) modifiers for
serviceA/B/C and inject values via method
Usually it makes sense to have more specific method name like
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!
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!
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).
That’s it! See repo playgrounds.
That’s my first article, I hope it was helpful! 👏👏👏