According to this blog post and the currently highest voted answer to this Stack Overflow question, which in turn cites Apple's documentation, the best way to create a singleton in modern Swift is:
class Singleton {
static let sharedInstance = Singleton()
}
Although it wasn't mentioned, probably a private init()
is called for as well.
To me, a simpler alternative would be to convert all properties and methods to static
, and drop the sharedInstance
property.
For example, suppose I wrote a class with a property and a method, following the advice above, as follows:
class Singleton {
static let sharedInstance = Singleton("whatever")
var myProperty: String
func myMethod() {
// ...
}
private init(_ myProperty) {
self.myProperty = myProperty
}
}
If the user needs to access the property in question, they would write Singleton.sharedInstance.myProperty
, and if they need to call the method, they would write Singleton.sharedInstance.myMethod()
.
I propose rewriting the class as follows:
class Singleton {
static var myProperty: String = "whatever"
static func myMethod() {
// ...
}
}
So: less boilerplate code, and less characters to type when accessing the property (just Singleton.myProperty
) and method (Singleton.myMethod()
).
One disadvantage is that accesses to the property and method from inside the class would need to be fully spelled out (Singleton.myProperty
and Singleton.myMethod()
), compared to just myProperty
and myMethod()
for the previous solution.
Thus, it's a little bit easier for the user (dropping the sharedInstance
part) and a little bit harder for the class writer (which needs to add Singleton.
in front of all accesses). It seems reasonable that, when faced with a design choice that either favors the user or the class writer, the better option is to favor the user.
Nobody else appears to advocate the method I proposed for making a singleton, so I get the feeling there must be something wrong with it. Would someone be so kind as to point out what is it?
While a static class allows only static methods and and you cannot pass static class as parameter. A Singleton can implement interfaces, inherit from other classes and allow inheritance. While a static class cannot inherit their instance members. So Singleton is more flexible than static classes and can maintain state.
Major difference between static and singleton is that Singleton can implemented Protocols and derive from some base classes. In case of Singleton , class can be instantiated but only once. Static functions can be used directly without instantiation.
The disadvantages of the singleton pattern become apparent the more complex your app gets. The more places in your app access the shared instance, the more unpredictable your app's behavior becomes and the harder it is to keep all your code in sync with the singleton's global state.
The Singleton pattern has several advantages over static classes. First, a singleton can extend classes and implement interfaces, while a static class cannot (it can extend classes, but it does not inherit their instance members).
To me, a simpler alternative would be to convert all properties and methods to static, and drop the sharedInstance property.
These do not do the same thing. The recommended approach is not actually a singleton at all. It's just a well-known instance. The concept of the Singleton pattern is that there must only be one instance. The concert of the shared instance pattern is that there can be more than one instance, but there is one that you probably want, and you would like easy access to it.
The advantage of shared instances is that they are not magical. They're just instances. That means that they can be handed around as values. They can be replaced with other instances that may be configured differently. They are easier to test (because they can be passed into functions).
True singletons are a very rigid pattern that should only be used when it is absolutely necessary that no other instance exist, usually because they interact with some external unique resource in a way that would create conflicts if there were multiples (this is pretty rare). Even in this case, in Swift, you should generally just make init
private to prevent additional instances being created.
If you look around Cocoa, you'll find that shared instances are extremely common for things that would be Singletons in other frameworks, and this has been very powerful. For instance, there is a well known NotificationCenter
called default
, and it's probably the only one you've ever used. But it's completely valid to create a private NotificationCenter
that's independent (I've actually done this in production code).
The fact that UIDevice.current
is how you access the device, rather than static methods, leaves open the possibility of new APIs that can handle multiple devices (it also helps with unit testing). In the earliest versions of iOS, the only UIScreen
was .main
, and it might have made sense to make it a singleton. But because Apple didn't, when mirroring was added in 4.3, it was simple to talk about the second screen (UIScreen.mirrored
). You should generally be very slow to assume that there can only be one of something.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With