Singletons In Swift Explained

A singleton is a class of which exactly one instance exists, that can be globally accessed. How do you create a singleton in Swift? And why should or shouldn’t you?

In this article, we’ll dive into singletons in Swift. You learn what the singleton design pattern is, and why it’s useful. We’ll discuss the syntax for creating singletons in Swift. And we’ll get into good and bad use cases for singletons.

What Is A Singleton?

A singleton is a class of which only one instance exists. A few examples:

A company has only one CEO

An API class has only one serial request queue

An operating system has only one file system

A solar system body revolves around one gravitational point

An app that does I/O has only one default FileManager

An airplane has only one flight deck

The second attribute of a singleton is that it has a global point of access. You can access a singleton, eg. call functions on it, from anywhere in your app’s code.

So, to summarize:

A singleton is a class that has only one instance

It can be accessed globally, i.e. anywhere in your code

In practical iOS development, you use singletons often. Typical classes like NotificationCenter, UserDefaults, SKPaymentQueue and FileManager have shared or default properties that are singletons.

At other times, you may wish to create a singleton yourself. A good use case is an API class that exposes singleton instance via its shared property. You use API.shared.makeAPICall() to access the API through a single, unified instance. This allows you, for instance, to manage API calls serially.

Before we discuss when singletons are best used (and when not), let’s find out how to code a singleton in Swift.

Become a professionaliOS developer

Get started with iOS 13 and Swift 5

Sign up for my iOS development course to learn iOS development with Swift 5, and start your professional iOS career.

The API class is mostly the same. It’s still a singleton, and it still uses those staticlet shared = API() and privateinit() bits of code.

Here’s what’s changed:

The API class now has an isRequestPending property. This is where the danger begins… See how the isRequestPending boolean ensures that only one API request can be done at a time? (Note that isRequestPending is an instance property.)

The API class also has a makeAPIRequest() function. Imagine that we can use this function to get some data back from a webservice API, like Twitter’s. In the function, you can see that a request can only be made when no other request is currently pending.

The API class also has an onReturnAPIRequest() function. This function is invoked when the API request returns, i.e. online data has been downloaded into the app. The isRequestPending boolean is set to false again, and the request data is processed.

And here’s how we can use the API singleton anywhere in our code:

API.shared.makeAPIRequest()

There’s something else we need to discuss. The API class now manages something called state. You can see “state” as a feeling: you’re either happy or you’re sad, or you’re angry, and so on. You can switch from one state to the other.

The API class can switch between two states:

A state in which isRequestPending is false

A state in which isRequestPending is true

As you’ll learn in the next section, state and singletons can wreak all sorts of havoc on your code. Managing state poorly is the single biggest reason for singleton misuse.

When To Use Singletons

there must be exactly one instance of a class, and it must be accessible to clients from a well-known access point

when the sole instance should be extensible by subclassing, and clients should be able to use an extended instance without modifying their code

That’s complex, but what it boils down to is:

Use a singleton when your code requires no more than one instance of a class (i.e., the CEO in the company)

And when it must be accessible from anywhere in your code (i.e., the file system)

Another use case is subclassing. A global variable in your code can’t be easily subclassed, so that’s why you use a singleton class. Additionally, singletons can be unit tested by using dependency injection. You replace the API instance by an APIMock instance, and gain the ability to unit test API calls without making the actual network requests.

And when do you not use singletons? To answer that question, we’ll have to go back to the state principle we discussed earlier.

A common pitfall for beginner iOS developers is to manage state and its dependencies poorly. Imagine you’re building an app that uses the API class we worked with earlier.

Every time you expand the API class, you tack on more and more properties, such as:

A userID property that keeps track of the logged in user, once the login() API call has been made

A tweets property with Twitter data, once the getTweets() call has been made

A spinner property with a UIActivityIndicatorView that you add to a view controller when a request has started

At first, this makes a lot of sense to do. After all, the API class can be accessed anywhere in your code. So, in the Tweet View Controller you can use the API.shared.tweets array, and in the Settings Controller you can use userID to quickly tell the API whose settings to change.

Unfortunately, your state is now all over the place. The API class has dependencies to a bunch of classes that aren’t related to the single responsibility of the API class. Your code has become a bowl of spaghetti, all tangled up. The code may work OK, but it’s impossible to maintain and extend.

Let’s look at an example. The onReturnAPIRequest() function we defined earlier is on the brink of becoming tightly coupled…

Here’s what we’re considering:

The onReturnAPIRequest() is called when an API webservice request returns, i.e. when data comes into the app. This data needs to go somewhere – a Tweet View Controller for example. How do you pass the data from the API to the view controller?

An obvious choice is to just create a reference to the viewController in the API class. When the data comes in, you can code something like viewController.tweets = tweetsData. This is poor architecture, unfortunately, because now the API and the view controller are tightly coupled. It’s impossible (or hard) to unit test, and likely to create problems when extending either class.

It’s better to choose a mechanism that doesn’t tightly couple both classes. One option would be to pass a closure to onReturnAPIRequest(), which is executed when the request returns. This closure can then contain code to handle the incoming data. Another option would be to use NotificationCenter to pass the data to the view controller, or to use a Database class to handle the data.

The singleton design pattern has gained some controversy, simply because it’s easy to misuse. When using singletons, be mindful of state and dependencies. Just because it’s easy to have global access to state, it doesn’t mean it’s a good idea.

Become a professionaliOS developer

Get started with iOS 13 and Swift 5

Sign up for my iOS development course to learn iOS development with Swift 5, and start your professional iOS career.

Browse Topics

Swift Sandbox

Reinder de Vries

Reinder de Vries is a professional iOS developer. He teaches app developers how to build their own apps at LearnAppMaking.com. Since 2009 he has developed a few dozen apps for iOS, worked for global brands and lead development at several startups. When he’s not coding, he enjoys strong espresso and traveling.