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
FileManager.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.
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
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!