Justin Duke

Singletons in Swift

A quick, relatively boring post about how to handle singletons in Swift in case you’re like me and spent an inordinate amount of time deliberating between the various approaches:

Singleton a la global variable

The laziest and easiest way to do it is storing the singleton as a global variable:

let _SingletonSharedInstance = Singleton()

class Singleton  {
    class var sharedInstance : Singleton {
        return _SingletonSharedInstance

Advantages of this approach:

  • Lazy initialization! 1
  • It’s automatically threadsafe since you’re making it a constant.

The disadvantages of this approach are myriad:

  • Swift doesn’t have support for private variables, so you clutter the global namespace (and you know, it’s a public variable) 2
  • You can’t push it to a class-level constant 3
  • Nothing says ‘this is probably a bad approach’ like prepending a variableName with an underscore

Singleton a la dispatch_once

Basically a straight port of the traditional Objective-C approach to Swift:

class RetroSingleton {
    class var sharedInstance : RetroSingleton {
        struct Static {
            static var token : dispatch_once_t = 0
            static var instance : Singleton? = nil
        dispatch_once(& Static .token) {
            Static.instance = RetroSingleton()
        return Static.instance!

This is how Apple recommends you implement the pattern in Objective-C: for those unaware 4, dispatch_once is a command to do something exactly once – you pass it a token and a closure to execute once, ensuring that you only hit the instantiation one time. This, like the global approach, is thread-safe and lazy: there aren’t any specific disadvantages here, but it’s not a particularly aesthetic approach.

Singleton a la nested struct

My preferred solution to the pattern (for the time being), as I find it the prettiest:

class NestedSingleton {

    class var sharedInstance : NestedSingleton {
        struct Static {
            static let instance : NestedSingleton = NestedSingleton()
        return Static.instance


Unlike classes, structs do support static constants! So we create a class-level property for the singleton class which, when accessed, grabs the struct with the singleton’d property and returns it. Since we declare the singleton’d property with let, it shares the advantages of the previous two approaches (and only has to be calculated once.) In Barback, it looks something like this:

class AllRecipes {
    class var sharedInstance : Recipe[] {
        struct Static {
            static let instance : Recipe[] = Static.allRecipes()
            static func allRecipes() -> Recipe[] {
                let filepath = NSBundle.mainBundle().pathForResource("recipes", ofType: "json")
                let jsonData = NSString.stringWithContentsOfFile(filepath, encoding:NSUTF8StringEncoding, error: nil)
                let recipeData = jsonData.dataUsingEncoding(NSUTF8StringEncoding)
                var rawRecipes = NSJSONSerialization.JSONObjectWithData(recipeData, options: nil, error: nil) as NSDictionary[]

                var allRecipes = rawRecipes.map({
                    (rawRecipe: NSDictionary) -> Recipe in
                    return Recipe(rawRecipe: rawRecipe)
                allRecipes = sort(allRecipes) { $0.name < $1.name }
                return allRecipes
        return Static.instance

That’s all the approaches I’ve found. If there are other options that I haven’t considered or considerations that I haven’t made 5, lemme know! Hope this helps.

  1. See [here](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html#//apple_ref/doc/uid/TP40014097-CH14-XID_337 [return]
  2. As of beta 4, this is no longer true. Access control is now a thing. [return]
  3. Though Chris Lattner has mentioned that this is an eventual possibility! [return]
  4. Like myself, until very recently! [return]
  5. This is very likely. [return]
Liked this post? You should subscribe to my newsletter and follow me on Twitter.

(I've got an RSS feed, too, if you'd prefer.)