Per settembre 2015, ecco esattamente come si effettua un singleton in Swift:
public class Model { static let shared = Model() // ( for ocd friends ... private init() {} ) func test()->Double { return 3.33 } }
poi altrove …
// file ViewController.swift, say import UIKit class ViewController:UIViewController { override func viewDidLoad() { super.viewDidLoad() print("view controller loaded!") print("singleton test! \( Model.shared.test() )") } }
Nessun problema.
public let model = Model.shared public class Model { static let shared = Model() func test()->Double { return 3.33 } }
quindi, puoi semplicemente fare il seguente progetto:
class ViewController:UIViewController { override func viewDidLoad() { super.viewDidLoad() print("view controller loaded!") print("singleton test! \( model.test() )") } }
Idioma convenzionale:
“mio” idioma:
Quindi, questo si traduce in tutto ciò che sembra carino:
(Nel tuo progetto, quelle “variabili singleton” sarebbero cose come i scores.
, Il networking.
, L’ heuristics.
O qualunque cosa possa essere nel tuo progetto.)
Questo quindi, è un idioma “macro-like”.
L’unico scopo è l’aspetto del codice.
Semplificazione delle apparizioni di ImportantSystem.SharedImportantSystem
su importantSystem.
per tutto il progetto.
I problemi possono essere tecnici, stilistici o di qualsiasi altra categoria, purché siano davvero profondi.
Funzionalmente, questi sono molto simili, ma consiglierei di usare la syntax Model.shared
perché questo rende assolutamente chiaro, ovunque lo si usi, che si ha a che fare con un singleton, mentre se si ha quel model
globale che fluttua là fuori , non è chiaro con cosa hai a che fare.
Inoltre, con i globals (esp con un semplice nome come “model”), si rischia di avere qualche class futura che ha variabili con nomi simili e accidentalmente fa riferimento a quella sbagliata.
Per una discussione sulle considerazioni generali riguardanti globals v singletons v altri pattern, vedere Global Variables Are Bad che, nonostante il titolo abbastanza importante, presenta una discussione sobria, ha alcuni link interessanti e presenta alternative.
A proposito, per i tuoi “amici OCD” (all’interno dei quali suppongo di dover contare su me stesso, perché penso che sia la migliore pratica), non solo dichiarerei init
come private
, ma probabilmente dichiarerai l’intera class come final
, per evitare la sottoclass (a quel punto diventa ambiguo a quali riferimenti shared
).
Ci sono alcune cose a cui prestare attenzione quando si utilizza questo approccio:
Una variabile globale di per sé non è un grosso problema, ma se si hanno abbastanza variabili globali, si potrebbe avere problemi con il completamento automatico, perché suggerirà sempre queste variabili globali.
Un altro problema con le variabili globali è che potresti avere un altro modulo nella tua applicazione (scritto da te o in altro modo) che definisce la stessa variabile globale. Questo causa problemi quando si usano questi 2 moduli insieme. Questo può essere risolto utilizzando un prefisso, come le iniziali della tua app.
L’uso di variabili globali è generalmente considerato una ctriggers pratica .
Un singleton è utile quando si lavora con un controller o un repository. Viene creato una volta e crea tutto ciò da cui dipende. Può esserci un solo controller e apre solo una connessione al database. Ciò evita molti problemi quando si lavora con risorse o variabili a cui è necessario accedere da tutta la tua app.
Ci sono tuttavia degli svantaggi, come la testabilità. Quando una class usa un singleton, il comportamento di quella class è ora influenzato dal comportamento dei singletons.
Un altro ansible problema è la sicurezza dei thread. Quando si accede a un singleton da thread diversi senza il blocco, possono verificarsi problemi difficili da eseguire il debug.
Si dovrebbe prestare attenzione quando si definiscono le variabili globali e si lavora con i singleton. Con la cura appropriata, non dovrebbero sorgere molti problemi.
Non riesco a vedere un singolo svantaggio di questo approccio:
Model.shared.test()
non ha senso se ci pensi, vuoi solo chiamare test, perché dovrei chiamare shared
quando ho solo bisogno di una funzione. In generale, mettendo da parte l’idioma esatto in discussione, per quanto riguarda l’uso dei singleton:
static var shared = Model()
come una specie di macro in un singleton, come suggerito in questo Q, si può semplicemente definire let model = Model()
che crea semplicemente un normale globale (non correlato a single). private init() {}
alla tua class, in modo che venga inizializzato solo una volta (notando che init
potrebbe ancora essere chiamato nello stesso file).