Quelle est la raison exacte de l'utilisation de 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 j'y compte immédiatement, mais dispatch_once prend jusqu'à Noël pour créer mon objet? Il ne revient pas immédiatement non? Au moins, cela semble être tout l'intérêt de Grand Central Dispatch.
Alors pourquoi font-ils ça?
ios
objective-c
singleton
automatic-ref-counting
Membre fier
la source
la source
Note: static and global variables default to zero.
Réponses:
dispatch_once()
est absolument synchrone. Toutes les méthodes GCD ne font pas les choses de manière asynchrone (dans le cas présent, ellesdispatch_sync()
sont synchrones). L'utilisation dedispatch_once()
remplace l'idiome suivant:L'avantage de
dispatch_once()
cela est que c'est plus rapide. Il est également plus propre sur le plan sémantique, car il vous protège également de plusieurs threads faisant l'allocation init de votre instance partagée - s'ils essaient tous en même temps. Il ne permettra pas la création de deux instances. L'idée dedispatch_once()
"faire quelque chose une fois et une seule fois", c'est précisément ce que nous faisons.la source
dispatch_once()
est vraiment simple (en particulier parce que Xcode va même le compléter automatiquement dans un extrait de code complet pour vous) et signifie que vous n'avez même jamais à vous demander si la méthode doit être thread-safe.+initialize
se produit avant que la classe ne soit touchée, même si vous n'essayez pas encore de créer votre instance partagée. En général, l'initialisation paresseuse (créer quelque chose uniquement en cas de besoin) est préférable. Deuxièmement, même votre revendication de performance n'est pas vraie.dispatch_once()
prend presque exactement la même quantité de temps que direif (self == [MyClass class])
dans+initialize
. Si vous en avez déjà un+initialize
, alors oui, la création de l'instance partagée est plus rapide, mais la plupart des classes n'en ont pas.Parce qu'il ne fonctionnera qu'une seule fois. Donc, si vous essayez d'y accéder deux fois à partir de différents threads, cela ne posera pas de problème.
Mike Ash a une description complète dans son article de blog Care and Feeding of Singletons .
Tous les blocs GCD ne sont pas exécutés de manière asynchrone.
la source