Singletons in iOS

By appsoluts 9 Monaten agoNo Comments

Was? Singletons sind nicht gleich Singletons?

Singletons. Ein vielfach diskutiertes Thema in der Entwicklung. Viele sehen es als gutes Pattern an, andere sehen in Singletons auch häufig ein Anti-Pattern.

Wusstest du, dass Singleton (mit großem S) und singleton (mit kleinem s) unterschiedlich sind? Verrückt, oder? In dem folgenden Artikel betrachten wir die verschiedenen Möglichkeiten von Singletons in der iOS Entwicklung mit der Programmiersprache Swift.

Single-was? Was sind Singletons überhaupt?

Schauen wir mal auf das bekannte Buch Design Patterns — Gang of four. Hier steht Folgendes:

  1. “A class has only one instance throughout and no other instance can be created. Instantiating from the outside world should be restricted.”
  2. “The class itself should provide a way to access the sole instance and be responsible for keeping track of that instance.”

Zusammengefasst bedeutet dies, dass die Klasse selber dafür zuständig ist, keine Erstellung weiterer Instanzen zuzulassen.

Wie sieht das Ganze in Swift aus?

Hier bieten die Type Properties die Basis für das Singleton-Pattern. Diese gewährleisten, dass durch den Zugriff auf die Variable immer die gleiche Instanz zurückgegeben wird.

Arten von Singletons

Singleton

Bei Singleton mit einem großen “S” kann ausschließlich eine Instanz der Klasse erstellt werden.

Beispiel
class HTTPClient {

    static let shared = HTTPClient()
    
    private init() {}
    
}
let sharedInstance = HTTPClient.shared

In dieser Beispielklasse wird über die Variable shared eine Instanz der Klasse HTTPClient zurückgegeben. Durch das let wird sichergestellt, dass diese nicht veränderbar ist und lediglich einmal erstellt wird.

singleton

Bei singleton mit einem kleinen “s” gibt es neben der statischen Instanz auch die Möglichkeit, über einen öffentlichen Konstruktor weitere Instanzen zu erstellen.

Beispiel
import UIKit

class HTTPClient {

    static let shared = HTTPClient()
    
    init() {}
    
}
let sharedInstance = HTTPClient.shared
let instance2 = HTTPClient()

In diesem Beispiel wird deutlich, dass der Konstruktor nicht mehr privat ist und mehrere Instanzen erstellt werden können. Diese Art von Singletons wird eher selten verwendet, da sie sehr fehleranfällig ist. Durch das Erstellen mehrerer Instanzen kann man schnell den Überblick verlieren und ein inkonsistenter State entstehen. Auch Apple verwendet aktiv diese Art von Singletons. Unter anderem ist es möglich, die UserDefaults über UserDefaults.standard abzurufen. Zudem ist es über einen öffentlichen Konstruktor möglich, weitere Instanzen zu erstellen.

Soll ich denn jetzt Singletons nutzen oder nicht?

Eine Frage, welche nicht einfach beantwortet werden kann. Stell dir zu Beginn immer die Frage: Soll ich hier wirklich ein Singleton verwendet? Brauche ich es hier? Falls irgendetwas dagegen spricht, verzichte darauf. Es wirkt im ersten Moment vielleicht wie die “beste” und “leichteste” Lösung, aber im Verlauf stellst du fest, dass es Probleme mit sich bringen kann. Singletons können sehr schnell die Architektur deiner Software beeinflussen.

Wie kann ich Singletons testen?

Ich muss einen Test schreiben, in welchem ein Singleton involviert ist. Wie kann ich das? Ist das überhaupt möglich?

Kurze Antwort: Ja!

Auch wenn es häufig heißt, dass es nur schwer oder nicht möglich sei, Code zu testen: Du kannst Code testen, welcher Abhängigkeiten zu Singletons hat.

Beispiel
class ViewController: UIViewController {
    
    var httpClient = HTTPClient.shared
    
    func login() {
        httpClient.login()
    }
}

class HTTPClientMock: HTTPClient {
    
    override func login() {
        // Do mock stuff here
    }
}

class ViewControllerTests: XCTestCase {
    
    func test_login_anyExpectation() {
        let vc = ViewController()
        let httpClientMock = HTTPClientMock.shared
        vc.httpClient = httpClientMock
        vc.login()
    }
}

Das hier gezeigte Beispiel ist eine Möglichkeit z.B. ViewController zu testen, welche eine Abhängigkeit zu Singletons haben. Über Property Injection kann eine Mock-Klasse des HTTP-Clients hereingereicht und somit die login() Funktion überschrieben werden. Dies ist auch nur eine Möglichkeit, um Singletons zu testen, welche wir hier anhand eines einfachen Beispiels mal aufzeigen wollten.

Mutable Global shared state

Hmm, das sind nicht mal Singletons, werden aber trotzdem häufig als diese bezeichnet. Häufig wird static let shared in static var shared geändert, um diverses Verhalten zu ermöglichen. Doch genau dadurch ist es kein Singleton mehr, da es vollkommen dem Konzept eines Singletons widerspricht, indem es von außerhalb manipuliert werden kann.

Zusammenfassung

Rückblickend betrachtet gibt es in Swift verschiedene Arten von Singletons, welche genutzt werden können. Je nach Anwendungsfall kannst du die eine oder die andere Art der Singletons nutzen. Doch wie bereits erwähnt, solltest du Singletons nur nutzen, wenn du dir 100% sicher bist, dass du es brauchst. Jede Kleinigkeit, welche dagegen spricht, sollte als Warnsignal gesehen werden und die Nutzung infrage stellen.

Pros

  • Daten innerhalb des Singletons sind immer aktuell, da nur eine Instanz existiert
  • Wird erst initialisiert, wenn sie das erste Mal verwendet wird

Cons

  • Unit testing wird deutlich schwerer, da das Singleton “nach implementiert” werden muss
  • Singletons generieren versteckte Abhängigkeiten
  • Wird erst beim Beenden der App de-initialisiert -> Kann somit zu Memory-Leaks führen
Categories:
  Allgemein, App, App Entwicklung, Digitalisierung, Entwicklung, ios
this post was shared 0 times
 600

Leave a Reply

Your email address will not be published.

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.