Kill singletons in your iOS project using protocols.

I’m am here to kill your singletons with protocols. Let’s talk about a few reasons you might be tempted to use a singleton.
- Initialization with a specific configuration — Apple uses this one a lot with objects such as
UserDefaults.standard
orFileManager.default
. The convenience here is obvious everything about the object you are getting back is configured. - Global access — You don’t have to think about how these objects are passed around your app. When you need it, you ask for it through the singleton.
What is so bad about singletons? If you are like me you probably got excited when you first learned how to make and use them. As your dev skills get sharper though you quickly realize all the things highlighted in this classic Stack overflow thread.
I digress from the singleton debate. Ultimately a new pattern based around protocols is just another tool to let you modularize and access functionality. I think crusty the clown will approve of this one though.
So, code. UIViewController
(s) demand access to functionality that should be configured and encapsulated in other controllers (Think network controllers or core data controllers). They want access to many things like NSManagedObjectContext
(s), precisely configured URLSession
(s), or other reusable objects that need configuration. Take the Apollo iOS client for graphQL as an example. You will probably need to make GraphQL requests from many different parts of your app. There is a lot of configuration required to set up the ApolloClient
object correctly. Especially if you are using subscriptions. Here is a struct I have in one of my projects that sets this all up:
Would you want to do this in your UIViewController
‘s viewDidLoad()
method every time you needed a reference to the ApolloClient
to perform a GraphQL request? I hope not! Would you make a singleton? Maybe. Instead, lets lazily initialize this object only once at the AppDelegate
(The only true singleton in your app).
From here there are a few common patterns including making an extension on UIViewController
that can reference the AppDelegate
or passing the ApolloController
around the app to where it is needed.
Instead, let’s make a protocol with some default behavior.
Now, any class that want’s to be able to access the ApolloController
that lives in the AppDelegate
just has to conform to that protocol!
Thanks for reading. Please comment if you like this pattern or feel free to express yourself if it sucks!