I was re-watching WWDC16 video Core Location Best Practices and there were two phrases that stuck with me.
“You might also consider attaching it to your app delegate instead”.
“You might want to attach it to your app delegate”.
There is a bad patter of global shared instances usage in Apple world. And I believe this is caused by two reasons. Sample code from Apple is intended as demonstration and it’s easy to dump everything into app delegate. Because it’s so convenient to access variables from there. Just call:
The other culprit is storyboards. Maybe it’s just me, but I have never gotten along with these. You always try to use these in new project, but after some fighting you just give up and revert to old mode. One reason for fighting is because they unintentionally seem to force you to use shared instance pattern. Without shared instances juggling dependencies becomes just too cumbersome.
And as unit testing is not that common in iOS, you don’t really see the pain when using shared instances.
A long time ago I came to a pattern where all dependencies were given to created object. For example core data wrapper. You create common instance in AppDelegate and forward it to root controller. That one will forward it to created/presented children.
Code wise it felt cleaner, but was also not perfect. Forwarding multiple dependencies became also awkward. And in good old Objective-C days it created fun bugs. When you forgot to forward something and nothing was happening because there are no NullPointerExceptions.
With Swift and protocol extensions stumbled onto something I feel really happy with. I call it ‘injector pattern’.
First you create protocols for dependency requirements. Samples from Find movies to watch:
Classes needing shared resources will conform to these protocols. For injection logic we have protocol with default implementation:
Now when controllers push other controller that need dependencies, they will implement InjectionHandler and can perform the injection:
Because of the ! in swift, you will find out very quickly if dependencies injection was not done.
Maybe it’s not perfect, but it makes working with dependencies a lot cleaner. Controllers still know what they are presenting, but at least not too many details are leaked. Also working with injected dependencies, unit testing becomes simpler.
Tags: ios, programming, injection