Singleton con propiedades en Swift 3

88

En el documento Uso de Swift con Cocoa y Objective-C de Apple (actualizado para Swift 3), dan el siguiente ejemplo del patrón Singleton:

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

        // setup code

        return instance
    }()
}

Imaginemos que este singleton necesita administrar una matriz variable de cadenas. ¿Cómo / dónde declararía esa propiedad y me aseguraré de que se inicialice correctamente en una [String]matriz vacía ?

RobertJoseph
fuente

Respuestas:

236

Para mí, esta es la mejor manera de hacer que init sea privado. Sintaxis 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
fuente
4
Voté esta respuesta, pero para que coincida con la sintaxis de Swift 3, "sharedInstance" debería cambiarse a solo "shared".
B-Rad
1
A menos que haya una regresión de swift 2 a swift 3, no es así
thibaut noah
1
El tipo después de compartido se puede omitir, ¿verdad? static let shared = Singleton()
chriswillow
1
@YannickSteph no tienes que escribir static let shared: Singleton = Singleton()en su lugar, solo puedes escribirstatic let shared = Singleton()
chriswillow
3
@RomanN No, no puedes anular init porque no hereda una clase. Si puede hacer eso, con este ejemplo final class Singleton: NSObject { private override init() { } }
YannSteph
59

Puede inicializar una matriz vacía como esta.

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

O si prefiere un enfoque diferente, este funcionará bien.

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

fuente
¿Este método no funciona en una extensión? extension Cache { static let sharedInstance: Cache = { let instance = Cache() return instance }() }
Andy
1
Interesante que Apple usa class varen iOS 10 para singletons (por ejemplo, UIApplication). ¿Su implementación sería la misma que esta?
jjatie
2
Prefiero los métodos de inicio de singleton como privatemétodos ni siquiera internal. Esto evita que otros usen el inicializador '()' predeterminado para esta clase.
Kumar C
1
@KumarC Tiene razón, ¿no resolver el problema si añadimos una privateen init.
@TikhonovAlexander ¿Podría traer más información?
Dominique Vial
30

Según la documentación de Apple: en Swift, simplemente puede usar una propiedad de tipo estático, que se garantiza que se inicializará perezosamente solo una vez, incluso cuando se accede a través de varios subprocesos simultáneamente .

class Singleton {

    // MARK: - Shared

    static let shared = Singleton()
}

Con método de inicialización:

class Singleton {

    // MARK: - Shared

    static let shared = Singleton()

    // MARK: - Initializer

    private init() {
    }

}
Mehul Sojitra
fuente
3
¿Por qué init () no es privado?
XcodeNOOB
0

Cualquier inicialización se haría en un método init. No hay diferencia aquí entre un singleton y un non-singleton.

gnasher729
fuente
26
Un fragmento de código adicional que responda directamente a la pregunta haría que esta respuesta fuera más útil.
Reda Lemeden