Creational Design Pattern — Singleton in iOS-Swift
In this Story, I going to show how to use Singleton easily. you can check the code at the end of the story.
Singleton
Ensures that there’s only one instance of a type.
I’m going to show how to implement the singleton and will also address the most significant challenge in this pattern.
singleton is one of the simple design patterns, but it’s also the most misused one. if implement it’s incorrectly, it turns to anti-pattern!
Usage
Singletons can serve you well if there’s a single resource and you need to access and manage that single instance throughout your application.
The UIApplication object is a good example. We need one in every IOS app, but we shouldn’t have more than one.
Misusing Singletons
- Reading singletons as global multipurpose containers is a classic example of abusing this pattern.
Using Singletons as global shared state goes against the single responsibility principle which tells us that each type should have one well-defined responsibility.
- Another issue with singletons is that once you start using them, they tend to spread across your codebase.
Eventually, you lose track of the objects that depend on the singletons.
These dependencies are hidden since you don’t have to pass the singleton to a method, an initializer, or assign it to a property of a type to use it.
Thus, our project may appear as being loosely coupled, whereas it’s not. And you will find this out the hard way.
Changing the singleton requires refactoring lots of other seemingly unrelated components.
This ripple effect is quite a common problem in projects that rely heavily on singletons and global instances.
- Performance problems due to synchronization if we forget to protect our singletons against concurrent usage.
On the other hand, a threat safe singleton might become a performance bottleneck if multiple threads are using it in parallel.
Implement Singleton design pattern
We are going to create a central config file for accessing from any part of the application.
This is a perfect candidate for the Singleton since creating more than one object of this type would be leading application to issue.
Create a new Swift file, and call it AppConfig.
Then declare a variable of type [String: Any] and put some default value on it.
We’re about to implement a Singleton, so we need to prevent clients from instantiating it directly. we can achieve that by hiding the initializer.
The private keyword ensures that the initializer can only be used within the class declaration and its extensions that are in the same file.
Currently, we’re not able to create any instances of the AppSettings class, so let’s do something about that.
declare public static property to access the shared object of the class.
Swift guarantees that static properties are threat-safe. That means that we shouldn’t worry about accidentally creating multiple AppSettings instances if multiple threats access the static property at once.
also, we need to declare some method to access the configs variable.
there is no issue if only read from singleton! if add method for set data in configs variable, it may cause issues in concurrency. to avoid that issue, we should make our singleton class thread-safe.
To avoid that issue, we use DispatchQueue, to sync tasks. DispatchQueue guarantee that task gets executed one at a time. but serializing the method causes performance issues.
Also, to avoid performance issues, we can separate reading and writing. Thus, we could allow concurrent read operations which would bring performance improvements.
we use dispatch barriers to solves this problem. The barrier changes the concurrent queue into a serial queue for as long as it takes to process the barrier block after which it reverts to a concurrent queue. Thus, it prevents race conditions and data corruption in parallel writing and reading.
Our Singleton is not only thread-safe but also optimized for performance.
Singletons aren’t inherently evil, but it’s easy to misuse them.
Therefore, think twice before introducing a Singleton. Ask yourself whether you really need the Singleton behavior and if the answer is yes, make sure to assign it one clear responsibility and consider making it thread-safe.