Qualche motivo non usa una “variabile” singleton in Swift?

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.

Però. Aggiungo questa piccola cosa …

 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:

Model.shared.blah () … lo vedi ovunque nella base del codice

“mio” idioma:

model.blah () … lo vedi ovunque nella base del codice

Quindi, questo si traduce in tutto ciò che sembra carino:

inserisci la descrizione dell'immagine qui

(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.

Qualcuno può vedere problemi con questo idioma?

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:

La variabile globale

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 .

Il modello singleton

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.

Sommario

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:

  • Puoi usare variabili diverse per le diverse parti del programma (-> Nessuno spazio dei nomi che si va in pezzi se non ti piace questo, immagino)
  • È breve, carino, facile da usare e ha un senso quando lo leggi. Model.shared.test() non ha senso se ci pensi, vuoi solo chiamare test, perché dovrei chiamare shared quando ho solo bisogno di una funzione.
  • Usa lo spazio dei nomi globale pigro di Swift: la class viene allocata e inizializzata quando la usi la prima volta; se non lo usi mai, non viene nemmeno assegnato / inserito.

In generale, mettendo da parte l’idioma esatto in discussione, per quanto riguarda l’uso dei singleton:

  • Ricordiamo che, naturalmente, invece di usare 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).
  • Con i singleti di Swift, c’è stata una discussione che probabilmente vuoi aggiungere un private init() {} alla tua class, in modo che venga inizializzato solo una volta (notando che init potrebbe ancora essere chiamato nello stesso file).
  • Ovviamente, in generale, quando si considera l’uso di un singleton, se non si ha realmente bisogno di uno stato e dell’istanza della class stessa, è sufficiente utilizzare semplicemente le funzioni / proprietà statiche. È un errore comune utilizzare un singleton (per esempio, funzioni di tipo “calcolo”) in cui tutto ciò che è necessario è un metodo statico.