89

In Apple's Using Swift with Cocoa and Objective-C document (updated for Swift 3) they give the following example of the Singleton pattern:

class Singleton {
    static let sharedInstance: Singleton = {
        let instance = Singleton()

        // setup code

        return instance
    }()
}

Let's imagine that this singleton needs to manage a variable array of Strings. How/where would I declare that property and ensure it gets initialized properly to an empty [String] array?

RobertJoseph
  • 7,336
  • 9
  • 58
  • 100

4 Answers4

237

For me this is the best way, make init private. Swift 3 \ 4 \ 5 syntax

// MARK: - Singleton

final class Singleton {

    // Can't init is singleton
    private init() { }

    // MARK: Shared Instance

    static let shared = Singleton()

    // MARK: Local Variable

    var emptyStringArray = [String]()

}
YannSteph
  • 9,590
  • 3
  • 49
  • 46
  • 4
    I upvoted this answer, but to match Swift 3 syntax, "sharedInstance" should be changed to just "shared". – B-Rad Apr 19 '17 at 20:46
  • You don't need to cast the type though – thibaut noah Apr 20 '17 at 09:31
  • @thibautnoah you need, in init or directly – YannSteph Apr 20 '17 at 17:26
  • 1
    Unless there is a regression from swift 2 to swift 3 you don't – thibaut noah Apr 21 '17 at 08:10
  • 1
    The type after shared can be omitted, right? `static let shared = Singleton()` – chriswillow Apr 25 '17 at 10:59
  • @KaraBenNemsi What do you mean with omitted ? – YannSteph Apr 25 '17 at 18:40
  • 1
    @YannickSteph you do not have to write `static let shared: Singleton = Singleton()` instead you can just write `static let shared = Singleton()` – chriswillow Apr 26 '17 at 10:54
  • The answer is correct but according to the Swift 3 syntax `override` should be applied to `init` method. `override private init() {}` instead of just `private init() { }` – RomanN Jul 14 '17 at 22:17
  • Something to keep in mind, because this is static, it'll be initialized on application startup. An exception will therefore prevent the application from starting. Also if you're accessing resources from a database or service on startup, this can have a serious performance impact on your application startup. – Nitesh Jul 17 '17 at 05:56
  • @Nitesh Yes, but It's up to you to manage the instance of your singleton – YannSteph Jul 20 '17 at 20:06
  • 3
    @RomanN No you can't override init because it does not inherit a class. If you can do that, with this example ```final class Singleton: NSObject { private override init() { } } ``` – YannSteph Jul 20 '17 at 20:09
  • 1
    What if I want to mock Singleton? – Hossam Ghareeb Aug 07 '17 at 11:51
  • @HossamGhareeb remove final for the test ```class Singleton { ... } / class MockSingleton: Singleton { ... }``` – YannSteph Aug 08 '17 at 20:30
  • 1
    would be great if they did like in Kotlin lang (`object` instead of `class`, that's all you need for Singleton, nothing more) – user25 Mar 08 '19 at 20:35
  • @Nitesh static variables are lazily initialized in Swift - they're not all initialized at startup – Bill Dec 15 '19 at 19:21
59

You can initialize an empty array like this.

class Singleton {

    //MARK: Shared Instance

    static let sharedInstance : Singleton = {
        let instance = Singleton(array: [])
        return instance
    }()

    //MARK: Local Variable

    var emptyStringArray : [String]

    //MARK: Init

    init( array : [String]) {
        emptyStringArray = array
    }
}

Or if you prefer a different approach, this one will do fine.

class Singleton {

    //MARK: Shared Instance

    static let sharedInstance : Singleton = {
        let instance = Singleton()
        return instance
    }()

    //MARK: Local Variable

    var emptyStringArray : [String]? = nil

    //MARK: Init

    convenience init() {
        self.init(array : [])
    }

    //MARK: Init Array

    init( array : [String]) {
        emptyStringArray = array
    }
}
  • Does this method not work in an extension? ```extension Cache { static let sharedInstance: Cache = { let instance = Cache() return instance }() }``` – Andrew Jul 22 '16 at 23:04
  • 1
    Interesting that Apple uses `class var` in iOS 10 for singletons (e.g. UIApplication). Would their implementation be the same as this? – jjatie Aug 11 '16 at 17:24
  • 2
    I prefer singleton init methods as `private` methods not even `internal`. This prevents others from using the default '()' initializer for this class. – Kumar C Sep 18 '16 at 07:22
  • 1
    @KumarC You are correct, would not it solve the issue if we add a ```private``` in ```init```. –  Sep 18 '16 at 09:06
  • @TikhonovAlexander Could you bring more informations? – Dominique Vial Jan 20 '17 at 09:34
  • I'm not sure that accessing to `emptyStringArray` thread safe, but on the other hand value types in swift are thread safe, so `emptyStringArray` is array, arrays is value type, perhaps it's thread safe. – Tikhonov Alexander Jan 21 '17 at 07:46
30

As per the apple's documentation: In Swift, you can simply use a static type property, which is guaranteed to be lazily initialized only once, even when accessed across multiple threads simultaneously.

class Singleton {

    // MARK: - Shared

    static let shared = Singleton()
}

With initialization method:

class Singleton {

    // MARK: - Shared

    static let shared = Singleton()

    // MARK: - Initializer

    private init() {
    }

}
Mehul Sojitra
  • 1,145
  • 9
  • 15
0

Any initialisation would be done in an init method. No difference here between a singleton and a non-singleton.

gnasher729
  • 47,695
  • 5
  • 65
  • 91