4

I'm creating a singleton class in Swift as follows:

class SingletonClass {

    class var sharedInstance: SingletonClass {
        struct Singleton {
            static let instance = SingletonClass()
        }

        return Singleton.instance
    }


    var a: Int?
    var b: Int?
    var c: Int?
}

This allows me to access a shared instance from anywhere:

SingletonClass.sharedInstance

While this works, it doesn't make this instance the only possible one in the entire system, which is what singletons are all about.
That means that I can still create a whole new instance such as this:

let DifferentInstance: SingletonClass = SingletonClass()

And the shared instance is not the only one anymore.

So my question is this: Is there a way in Swift to create a true singleton class, where only one instance is possible system-wide?

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Darkshore Grouper
  • 693
  • 1
  • 9
  • 20
  • why would you want to enforce that no one can create an instance of a class? – Daniel Galasko Nov 12 '14 at 17:05
  • 1
    @DanielGalasko, say for example, if you have a physical resource that your class is managing the interaction with. It is possible that multiple instances interacting with the same resource would cause significant or fatal problems. Or perhaps it is just interacting with a database that cannot be opened more than once at a time. – drewag Nov 12 '14 at 23:09
  • I hear you, but unfortunately there is no means of defending your framework against someone else's ignorance or stupidity. Your best option is to define most of the objects setup methods inside of the singletons instantiation, like the database urls etc... – Daniel Galasko Nov 13 '14 at 07:23

3 Answers3

14

Just declare your initializer as private:

private init() {}

Now new instances can only be created from within the same file.

drewag
  • 93,393
  • 28
  • 139
  • 128
2

You have misunderstood the nature of singleton. The purpose of singleton is provide a singleton, not to prevent evil. I can make another UIApplication instead of the sharedApplication but that would be stupid since it would not be the sharedApplication. I can make another NSNotificationCenter instead of the defaultCenter but that would be stupid since it would not be the defaultCenter. The point is not to stop me from stupidity but to provide a factory singleton, and that is what you are already doing. Don't worry, be happy.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • I was just about to comment the same thing. Almost impossible to prevent "stupidity" (for lack of a better word). If people want to allocate new instances then let them, just document that its not the way to go about doing it and that said behaviour is undefined – Daniel Galasko Nov 12 '14 at 17:07
  • 1
    Yes, well, I'm a little torn between "stupid" and "evil" which is why I used both. :) OOP programming is a _contract_. Anyone can break the contract (for example, you can always evade privacy restrictions if you really want to). The idea, however, is not to. – matt Nov 12 '14 at 17:09
  • 3
    However, one of the main concepts in usability is the idea of affordances. Reducing what is possible makes something easier to use. Especially when the solution is as easy as making the initializer private (see my answer), I think it is better to do so. Also, the first line on wikipedia for singleton is "In software engineering, the singleton pattern is a design pattern that restricts the instantiation of a class to one object." There is a difference between a shared instance and a singleton. – drewag Nov 12 '14 at 17:11
  • Also, the idea of having multiple notification centers isn't crazy, but the idea of having multiple Camera objects, for example, when there is only one on the computer is not only illogical, but can cause serious problems at a low level. Sometimes true singletons (enforcing a single instance) is actually necessary to prevent serious crashes or bugs. – drewag Nov 12 '14 at 17:20
  • 1
    @matt I actually have to agree with drewag here. You gave perfect examples of classes with shared instances that would be pretty foolish not to use :). But those are only very useful shared instances, not singletons. A singleton class, by definition, can only have one existing instance at any given time. In my current specific case btw, it's actually not that important that I use a true singleton, but it was interesting to me to raise the question of how to do so. Somehow, I managed to miss the obvious private init solution. I guess it's the work load :) – Darkshore Grouper Nov 12 '14 at 23:04
  • Well I'm glad I elicited this discussion. :) – matt Nov 13 '14 at 00:58
  • The "defensive programming" debate... I side with this answer. – Nicolas Miari Jan 18 '16 at 08:10
0

Global variables, Nested struct, dispatch_once. Choose one.

The lazy initializer for a global variable (also for static members of structs and enums) is run the first time that global is accessed, and is launched as dispatch_once to make sure that the initialization is atomic. This enables a cool way to use dispatch_once in your code: just declare a global variable with an initializer and mark it private.

private let _singletonInstance = SingletonClass()
class SingletonClass {
  class var sharedInstance: SingletonClass {
    return _singletonInstance
  }
}

More info here. https://github.com/hpique/SwiftSingleton

Mark McCorkle
  • 9,349
  • 2
  • 32
  • 42