Singleton com propriedades em Swift 3

88

No documento Using Swift with Cocoa e Objective-C da Apple (atualizado para o Swift 3), eles fornecem o seguinte exemplo do padrão Singleton:

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

        // setup code

        return instance
    }()
}

Vamos imaginar que este singleton precisa gerenciar um array variável de Strings. Como / onde eu declararia essa propriedade e garantir que ela seja inicializada corretamente em uma [String]matriz vazia ?

RobertJoseph
fonte

Respostas:

236

Para mim, esta é a melhor maneira, tornar o init privado. Sintaxe Swift 3 \ 4 \ 5

// 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
fonte
4
Eu votei a favor dessa resposta, mas para corresponder à sintaxe do Swift 3, "sharedInstance" deve ser alterado para apenas "shared".
B-Rad de
1
A menos que haja uma regressão de swift 2 para swift 3, você não
thibaut noah
1
O tipo depois de compartilhado pode ser omitido, certo? static let shared = Singleton()
chriswillow,
1
@YannickSteph, você não precisa escrever, static let shared: Singleton = Singleton()basta escreverstatic let shared = Singleton()
chriswillow
3
@RomanN Não, você não pode sobrescrever o init porque ele não herda uma classe. Se você pode fazer isso, com este exemplo final class Singleton: NSObject { private override init() { } }
YannSteph
59

Você pode inicializar um array vazio como este.

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
    }
}

Ou se você preferir uma abordagem diferente, esta será adequada.

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
    }
}

fonte
Este método não funciona em uma extensão? extension Cache { static let sharedInstance: Cache = { let instance = Cache() return instance }() }
Andy
1
Interessante que a Apple usa class varno iOS 10 para singletons (por exemplo, UIApplication). A implementação deles seria igual a esta?
jjatie
2
Eu prefiro métodos de inicialização singleton como privatemétodos nem mesmo internal. Isso evita que outros usem o inicializador padrão '()' para esta classe.
Kumar C
1
@KumarC Você está correto, não resolveria o problema se adicionarmos um privateem init.
@TikhonovAlexander Você poderia trazer mais informações?
Dominique Vial
30

De acordo com a documentação da apple: No Swift, você pode simplesmente usar uma propriedade de tipo estático, que tem a garantia de ser inicializada lentamente apenas uma vez, mesmo quando acessada através de vários threads simultaneamente .

class Singleton {

    // MARK: - Shared

    static let shared = Singleton()
}

Com método de inicialização:

class Singleton {

    // MARK: - Shared

    static let shared = Singleton()

    // MARK: - Initializer

    private init() {
    }

}
Mehul Sojitra
fonte
3
porque o init () não é privado?
XcodeNOOB de
0

Qualquer inicialização seria feita em um método init. Nenhuma diferença aqui entre um singleton e um não singleton.

gnasher729
fonte
26
Um trecho de código adicional que responde diretamente à pergunta tornaria essa resposta mais útil.
Reda Lemeden