Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift singleton vs. static properties/methods

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?

like image 796
swineone Avatar asked Jan 25 '19 17:01

swineone


People also ask

Why use a singleton instead of static methods?

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.

What is the difference between singleton and static class Swift?

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.

What are the disadvantages of Singleton pattern Swift?

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.

Should I use singleton or static class?

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).


1 Answers

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.

like image 192
Rob Napier Avatar answered Sep 19 '22 08:09

Rob Napier