web-dev-qa-db-fra.com

Pourquoi Apple recommande-t-il d'utiliser dispatch_once pour implémenter le modèle singleton sous ARC?

Quelle est la raison exacte d'utiliser dispatch_once dans l'accesseur d'instance partagée d'un singleton sous ARC?

+ (MyClass *)sharedInstance
{
    //  Static local predicate must be initialized to 0
    static MyClass *sharedInstance = nil;
    static dispatch_once_t onceToken = 0;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[MyClass alloc] init];
        // Do any other initialisation stuff here
    });
    return sharedInstance;
}

N'est-ce pas une mauvaise idée d'instancier le singleton de manière asynchrone en arrière-plan? Je veux dire, que se passe-t-il si je demande cette instance partagée et que je m'en sers immédiatement, mais dispatch_once prend jusqu'à Noël pour créer mon objet? Ca ne revient pas tout de suite non? Au moins, cela semble être l’essentiel du Grand Central Dispatch.

Alors pourquoi font-ils cela?

302
Proud Member

dispatch_once() est absolument synchrone. Toutes les méthodes GCD ne font pas les choses de manière asynchrone (le cas d'espèce, dispatch_sync() est synchrone). L'utilisation de dispatch_once() remplace l'idiome suivant:

+ (MyClass *)sharedInstance {
    static MyClass *sharedInstance;
    @synchronized(self) {
        if (sharedInstance == nil) {
            sharedInstance = [[MyClass alloc] init];
        }
    }
    return sharedInstance;
}

L'avantage de dispatch_once() par rapport à cela est que c'est plus rapide. Il est également sémantiquement plus net, car il vous protège également de plusieurs threads qui effectuent alloc init de votre instance partagée - s’ils essaient tous au même moment. Cela ne permettra pas la création de deux instances. Toute l'idée de dispatch_once() est "effectuer quelque chose une fois et une fois", et c'est précisément ce que nous faisons.

415
Lily Ballard

Parce qu'il ne fonctionnera qu'une fois. Donc, si vous essayez d'y accéder deux fois à partir de threads différents, cela ne posera pas de problème.

Mike Ash a une description complète dans son billet de blog Entretien et alimentation des singletons .

Tous les blocs GCD ne sont pas exécutés de manière asynchrone.

41
Abizern