Benefits and Risks of Singletons

Three singletons types frequently occur throughout iOS SDK and codebases. Let us name them and examine their benefits and risks. They are as follows:

class ExampleOne {
    static let shared = ExampleOne()

    private init {}
}
class ExampleTwo {
    static let shared = ExampleTwo()
}
class ExampleThree {
    static var sharedInstance = ExampleThree()
}

ExampleOne is by the book Singleton implementation. In Swift static let is a lazily loaded constant, which preserves system resources at launch. That class has only one instance. It provides a single point of access to it. As described in the Design Patterns book (GOF) it makes sure that the class itself keeps track of its sole instance and prohibits creating over one instance.

ExampleTwo depicts a variation of Singleton a.k.a. singleton with lowercase ‘s’. Take for example URLSession.shared or UserDefaults.standard. The code instantiates the class only one time in the whole life-cycle of the app. One difference between the Singleton and singleton is that the interface does allow creating a new instance of the class.

ExampleThree shows a mutable global shared state. Usually accessed by a variable named static var sharedInstance, it allows the access and mutation of that reference. This exemplifies Ambient Context anti-pattern. Apple uses it too. For instance URLCache.shared property is a static, globally accessible property that we can change.

Problems singletons cause

Frequent usage in unfortunate scenarios gave rise the singleton to be considered an anti-pattern.

Singletons can set up unnecessary restrictions in situations where a sole instance of a class is not required. If not carefully considered, they make dependencies implicit, highly couple modules, prevent testability, introduce global state and force thread-safety. Ambient Contexts are even worse. They allow changing the dependency causing problems such as temporal coupling, global state or runtime inconsistency.

When singletons suit

When one requires precisely one instance of a class, and it must be accessible to clients from a well-known access point. A case in point is a class that logs messages to the console. Its public API is simple and we don’t need over one instance or even re-create or mutate its reference in memory.

Bad Singleton candidates are all objects not mandatory to have only one instance in a system.

Access the concrete singleton instance directly should be avoided. To escape the tight coupling one can use dependency inversion. By hiding the third-party dependency behind an interface one can keep the app modules agnostic about the implementation details.

Conclusion

It is widely known that singletons may damage system design and testability, but when used as intended they are a useful tool.

References

Comment Rules: The goal is to become better at our jobs. To post code, insert it between the tags <code></code> Critical is fine, but if you’re rude, I'll delete your stuff. Please do not put your URL in the comment text and please use your PERSONAL name or initials and not your business name, as the latter comes off like spam. Have fun and thanks for adding value to the converstaion!

Leave a Reply

Your email address will not be published. Required fields are marked *