Singleton Design Pattern in Swift
Welcome there. You probably hear about design patterns if you are in to coding. It doesn’t matter which programming language you use, design patterns are created to solve the problems that programmers face frequently.
There are basically three types of design pattern. They are creational, structural and behavioral. Singleton is a creational design pattern which means, it will effect the creation of components through the program.
Definition of Singleton
The Singleton Design Pattern restricts the instantiation of a class to one object. This pattern ensures that there is only one instance of a particular class in the project and provides a global access to that instance. Whole pattern’s purpose is to provide only one instance throughout the application and make it global accessable which means accessable from any class, struct, actor etc. One instance means, this object can’t be instantiated more than one time therefore it’s initiliazer must be private.
Creation of Singleton
class NetworkManager {
static let shared = NetworkManager()
private init() { }
func fetchFromNetwork() {
// Some logic...
}
}
or
class IAPHelper {
static let sharedInstance = IAPHelper()
private init() { }
func purchaseProduct() {
// Some logic...
}
}
Instance’s name doesn’t matter as long as you name it something relative to one instance concept. These both pieces of code makes the initializer private which blocks the creation of this class from other places.
To use it;
NetworkManager.shared.fetchFromNetwork()
IAPHelper.sharedInstance.purchaseProduct()
Advantages and Disadvantages
Advantages
- Global access makes it super easy to use and modify the class’ properties throughout the system.
Disadvantages
- That one instance will be alive in the memory until the app is terminated which means even though you don’t use that instance, it will take some space in the memory.
- Enemy to unit testing, unit testing’s whole purpose is the testing of a case in an isolated environment, that means you mock classes and don’t instantiate the real class with their dependencies. When you try to test the Singleton class, you create the whole dependencies in that class even though you don’t need and since it is global, changing the state in one test will affect the result of the other tests.
- Enemy to dependency injection concept.
Important BONUS
Singleton vs singleton
Now you might be wondering, there are lots of disadvantages of the Singleton so therefore why should I use it in my project? That depends on your project’s requirements and your teammates but even Apple uses it in their libraries.
You have seen and used this code LOTS of times. Did you noticed that “shared” keyword after the URLSession?
URLSession.shared.dataTask(with: url) { data, response, error in }
Or the “standard” keyword after the UserDefaults?
UserDefaults.standard.bool(forKey: "isOnboardingDone")
Or in here?
But there is a catch in here. You can create your own URLSession object! That is not the purpose of the Singleton right? Yes this is not Singleton but Apple decided to name this pattern as “singleton” rather than “Singleton”. I believe this is a really interesting topic to discuss on it. Here is an example;
let config = URLSessionConfiguration.default
config.allowsCellularAccess = true
config.timeoutIntervalForRequest = 10
config.httpCookieAcceptPolicy = .never
let session = URLSession(configuration: config)
session.dataTask(with: url) { data, response, error in }
Why structs doesn’t work with Singleton?
class MyClassSingleton {
static let shared = MyClassSingleton()
private init() { }
var state = 10
func giveInfo() { print("From class singleton \(state)") }
}
struct MyStructSingleton {
static let shared = MyStructSingleton()
private init() { }
var state = 10
func giveInfo() { print("From struct singleton \(state)") }
}
Lets use them like so;
let classSingleton = MyClassSingleton.shared
classSingleton.state = 30
MyClassSingleton.shared.giveInfo() // prints "30"
var structSingleton = MyStructSingleton.shared
structSingleton.state = 30
MyStructSingleton.shared.giveInfo() // prints "10"
This is not what we expect right? Classes are reference types and structs are value types. That is the main reason you should not use structs as Singletons.
I hope you learnt something from the article. If you have any questions or suggestions, please contact me. Thank you for your time.
My Personal Website | GitHub | LinkedIn | Instagram | Twitter