Dispatch_once in Swift: Hauptfehler und richtige Alternativen

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Dispatch_once in Swift: Warum das ein Fehler ist und wie man einen korrekten Singleton schreibt

\n\n

Wenn Sie sich jemals gefragt haben: "Wie erstelle ich einen Singleton in Swift mit dispatch_once?" – sind Sie nicht allein. Auf Stack Overflow hat diese Frage tausende Aufrufe gesammelt, und im Code vieler Projekte finden sich immer noch seltsame Konstruktionen, die versuchen, den alten Objective-C-Ansatz zu emulieren. Die gute Nachricht ist jedoch, dass es in Swift eine viel elegantere und sicherere Lösung gibt. Die schlechte Nachricht: Viele Entwickler machen immer wieder dieselben Fehler, wenn sie versuchen, Gewohnheiten aus Objective-C nach Swift zu übertragen.

\n\n

In diesem Artikel analysieren wir die Top-5-Fehler bei der Verwendung von dispatch_once in Swift, zeigen, wie man sie vermeidet, und geben eine fertige Vorlage für einen korrekten Singleton. Los geht's!

\n\n

Was ist dispatch_once und warum wird es in Swift nicht benötigt?

\n\n

dispatch_once ist eine Funktion aus Grand Central Dispatch (GCD), die garantiert, dass ein Codeblock während der gesamten Laufzeit der Anwendung genau einmal ausgeführt wird. In Objective-C war dies die Standardmethode zur Erstellung threadsicherer Singletons:

\n\n
+ (instancetype)sharedInstance {\n    static MyClass *sharedInstance = nil;\n    static dispatch_once_t onceToken;\n    dispatch_once(&onceToken, ^{\n        sharedInstance = [[MyClass alloc] init];\n    });\n    return sharedInstance;\n}
\n\n

In Swift ab Version 1.0 wird dispatch_once nicht unterstützt für die Verwendung in benutzerdefiniertem Code. Ja, Sie können Dispatch importieren und versuchen, es aufzurufen, aber der Compiler wird dies nicht zulassen. Warum? Weil Swift integrierte Mittel bietet, die dispatch_once überflüssig machen.

\n\n

Top-5-Fehler bei der Verwendung von dispatch_once in Swift

\n\n

Fehler 1: Direkter Aufruf von dispatch_once

\n\n

Der häufigste Fehler ist der Versuch, so etwas zu schreiben:

\n\n
class MySingleton {\n    static var shared: MySingleton = {\n        let instance = MySingleton()\n        // Konfiguration\n        return instance\n    }()\n    \n    private init() {}\n}
\n\n

Auf den ersten Blick funktioniert das. Aber das ist kein dispatch_once. Es ist einfach eine globale Variable, die beim ersten Zugriff lazy initialisiert wird. Swift garantiert Threadsicherheit für solche statischen Eigenschaften, aber das ist nicht dasselbe wie dispatch_once.

\n\n

Warum ist das schlecht? Weil Sie die Kontrolle über den Initialisierungszeitpunkt verlieren. Wenn Ihr Singleton von externen Ressourcen (z. B. Datenbank oder Netzwerk) abhängt, sind diese möglicherweise noch nicht bereit.

\n\n

Fehler 2: Verwendung von dispatch_once über einen Objective-C-Wrapper

\n\n

Einige Entwickler erstellen eine Brücke zu Objective-C, um dispatch_once aus Swift aufzurufen:

\n\n
// Objective-C Datei\n@interface OnceHelper : NSObject\n+ (void)performOnce:(void(^)(void))block;\n@end\n\n@implementation OnceHelper\nstatic dispatch_once_t onceToken;\n+ (void)performOnce:(void(^)(void))block {\n    dispatch_once(&onceToken, block);\n}\n@end
\n\n

Dann in Swift:

\n\n
class MySingleton {\n    static var shared: MySingleton = {\n        var instance: MySingleton!\n        OnceHelper.performOnce {\n            instance = MySingleton()\n        }\n        return instance\n    }()\n}
\n\n

Was ist das Problem? Erstens ist es ein Workaround. Zweitens ist dispatch_once_t eine globale Variable, und wenn Sie vergessen, das Token zurückzusetzen (z. B. beim Testen), wird der Singleton nicht neu erstellt. Drittens empfiehlt Apple ausdrücklich, dispatch_once in Swift nicht zu verwenden.

\n\n

Fehler 3: Threadsicherheit vergessen

\n\n

Einige schreiben den Singleton so:

\n\n
class MySingleton {\n    static var shared: MySingleton?\n    \n    private init() {}\n    \n    static func getInstance() -> MySingleton {\n        if shared == nil {\n            shared = MySingleton()\n        }\n        return shared!\n    }\n}<                

Blogs

Buchempfehlungen