Dispatch_once en Swift : principales erreurs et alternatives correctes

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Dispatch_once en Swift : pourquoi c'est une erreur et comment écrire un singleton correct

\n\n

Si vous vous êtes déjà demandé « Comment créer un singleton en Swift avec dispatch_once ? » — vous n'êtes pas seul. Sur Stack Overflow, cette question a recueilli des milliers de vues, et dans le code de nombreux projets, on trouve encore des constructions étranges tentant d'émuler l'ancienne approche Objective-C. Mais la bonne nouvelle, c'est qu'il existe en Swift une solution bien plus élégante et sûre. La mauvaise nouvelle : de nombreux développeurs continuent de commettre les mêmes erreurs en essayant de transposer leurs habitudes d'Objective-C en Swift.

\n\n

Dans cet article, nous allons analyser le top 5 des erreurs lors de l'utilisation de dispatch_once en Swift, montrer comment les éviter, et fournir un modèle prêt à l'emploi pour un singleton correct. C'est parti !

\n\n

Qu'est-ce que dispatch_once et pourquoi n'est-il pas nécessaire en Swift ?

\n\n

dispatch_once est une fonction de Grand Central Dispatch (GCD) qui garantit qu'un bloc de code s'exécute exactement une fois pendant toute la durée de vie de l'application. En Objective-C, c'était la méthode standard pour créer des singletons thread-safe :

\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

Cependant, en Swift, depuis la version 1.0, dispatch_once n'est pas supporté pour une utilisation dans le code utilisateur. Oui, vous pouvez importer Dispatch et essayer de l'appeler, mais le compilateur ne le permettra pas. Pourquoi ? Parce que Swift propose des mécanismes intégrés qui rendent dispatch_once inutile.

\n\n

Top 5 des erreurs lors de l'utilisation de dispatch_once en Swift

\n\n

Erreur 1 : Tenter d'appeler dispatch_once directement

\n\n

L'erreur la plus courante est d'essayer d'écrire quelque chose comme :

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

À première vue, cela fonctionne. Mais ce n'est pas dispatch_once. C'est simplement une variable globale qui est initialisée paresseusement (lazy) lors de la première utilisation. Swift garantit la sécurité des threads pour ces propriétés statiques, mais ce n'est pas la même chose que dispatch_once.

\n\n

Pourquoi est-ce mauvais ? Parce que vous perdez le contrôle sur le moment de l'initialisation. Si votre singleton dépend de ressources externes (par exemple, une base de données ou le réseau), elles peuvent ne pas encore être prêtes.

\n\n

Erreur 2 : Utiliser dispatch_once via une enveloppe Objective-C

\n\n

Certains développeurs créent un pont Objective-C pour appeler dispatch_once depuis Swift :

\n\n
// Fichier Objective-C\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

Puis en 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

Quel est le problème ? Premièrement, c'est un bricolage. Deuxièmement, dispatch_once_t est une variable globale, et si vous oubliez de réinitialiser le jeton (par exemple, lors des tests), le singleton ne sera pas recréé. Troisièmement, Apple recommande explicitement de ne pas utiliser dispatch_once en Swift.

\n\n

Erreur 3 : Oublier la sécurité des threads

\n\n

Certains écrivent un singleton comme ceci :

\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

Book Recommendations