what is singleton class in swift
Singleton class means single instance , That means in coding language a class which object create once , Only one instance exist in whole project and globally accessible.
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.
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.
let’s find out how to code a singleton in Swift.
This is the best way to create a singleton in Swift:
class API
{
static let shared = API()
private init()
{
// Set up API instance
}
}
API.shared.doSomething()
We’re creating an API class that has one static property called shared. This property cannot be changed once set, because it’s a constant, and it’s declared statically.
That means we can access the shared property via the class API. This is often called a class property. Compare this to a normal instance property, which can only be accessed via an instance of a class.
What’s interesting is that the shared property initializes an instance of API within the API class. We’re sort of creating an API object that can be accessed through the API class. But there’s more…
The class initializer init() is marked with private. This private keyword ensures that the API class can only be initialized within the API class.
In other words, you cannot create an instance of API outside of the API class! This ensures that the API object we’ve created is the only instance in our code. After all, you can’t create more of it.
And now we’ve ensured the API class conforms to the two attributes of a singleton:
class API
{
static let shared = API()
var isRequestPending = false
private init() { }
func makeAPIRequest()
{
if isRequestPending {
return
}
isRequestPending = true
// Make the API HTTPS request...
}
func onReturnAPIRequest()
{
isRequestPending = false
// Do something with request data...
}
}
The API class is mostly the same. It’s still a singleton, and it still uses those static let shared = API() and private init() 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
When do you use singletons? The book Design Patterns: Elements Of Reusable Object-Oriented Software by the Gang of Four has the following to say. Use the singleton pattern when:
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?
Discover more from CODE t!ps
Subscribe to get the latest posts sent to your email.