Si vous pouvez cibler iOS 4.0 ou supérieur
À l'aide de GCD, est-ce le meilleur moyen de créer un singleton en Objective-C (thread safe)?
+ (instancetype)sharedInstance
{
static dispatch_once_t once;
static id sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
instancetype
. La complétion de code est bien meilleure lorsque vous l'utilisez au lieu deid
.Réponses:
C'est un moyen parfaitement acceptable et thread-safe de créer une instance de votre classe. Il peut ne pas être techniquement un "singleton" (en ce sens qu'il ne peut y avoir qu'un seul de ces objets), mais tant que vous n'utilisez la
[Foo sharedFoo]
méthode que pour accéder à l'objet, c'est suffisant.la source
type d'instance
instancetype
n'est qu'une des nombreuses extensions linguistiques deObjective-C
, avec plus étant ajouté avec chaque nouvelle version.Sachez-le, aimez-le.
Et prenez-le comme un exemple de la façon dont prêter attention aux détails de bas niveau peut vous donner un aperçu de nouvelles façons puissantes de transformer Objective-C.
Référez-vous ici: instancetype
la source
MySingleton.h
MySingleton.m
la source
init
?MySingleton
, par exemple dansMySingleton.m
j'appelle[super alloc]
Vous pouvez éviter que la classe soit allouée en remplaçant la méthode alloc.
la source
Dave a raison, c'est très bien. Vous voudrez peut-être consulter les documents d'Apple sur la création d'un singleton pour obtenir des conseils sur la mise en œuvre de certaines des autres méthodes pour vous assurer qu'une seule peut jamais être créée si les classes choisissent de NE PAS utiliser la méthode sharedFoo.
la source
Si vous voulez vous assurer que [[MyClass alloc] init] renvoie le même objet que sharedInstance (pas nécessaire à mon avis, mais certains le veulent), cela peut être fait très facilement et en toute sécurité en utilisant un second dispatch_once:
Cela permet à toute combinaison de [[MyClass alloc] init] et [MyClass sharedInstance] de renvoyer le même objet; [MyClass sharedInstance] serait juste un peu plus efficace. Fonctionnement: [MyClass sharedInstance] appellera une fois [[MyClass alloc] init]. Un autre code pourrait l'appeler aussi, un certain nombre de fois. Le premier appelant à init effectuera l'initialisation "normale" et stockera l'objet singleton dans la méthode init. Tout appel ultérieur à init ignorera complètement ce que alloc a renvoyé et renverra la même instance partagée; le résultat de l'allocation sera désaffecté.
La méthode + sharedInstance fonctionnera comme elle l'a toujours fait. Si ce n'est pas le premier appelant à appeler [[MyClass alloc] init], le résultat de init n'est pas le résultat de l'appel alloc, mais c'est OK.
la source
Vous demandez si c'est la "meilleure façon de créer un singleton".
Quelques réflexions:
Tout d'abord, oui, c'est une solution thread-safe. Ce
dispatch_once
modèle est le moyen moderne et sans fil de générer des singletons dans Objective-C. Pas de soucis là-bas.Vous avez cependant demandé si c'était la "meilleure" façon de procéder. Il faut cependant reconnaître que le
instancetype
et[[self alloc] init]
est potentiellement trompeur lorsqu'il est utilisé conjointement avec des singletons.L'avantage de
instancetype
c'est que c'est une façon non ambiguë de déclarer que la classe peut être sous-classée sans avoir recours à un type deid
, comme nous le faisions autrefois.Mais le
static
dans cette méthode présente des défis de sous-classement. Que faire siImageCache
etBlobCache
singletons étaient les deux sous - classes d'uneCache
superclasse sans mettre en oeuvre leur propresharedCache
méthode?Pour que cela fonctionne, vous devez vous assurer que les sous-classes implémentent leur propre
sharedInstance
méthode (ou tout autre nom pour votre classe particulière).En bout de ligne, votre original
sharedInstance
semble prendre en charge les sous-classes, mais ce ne sera pas le cas. Si vous avez l'intention de prendre en charge le sous-classement, incluez à tout le moins une documentation qui avertit les futurs développeurs qu'ils doivent remplacer cette méthode.Pour une meilleure interopérabilité avec Swift, vous souhaiterez probablement définir cela comme une propriété, pas une méthode de classe, par exemple:
Ensuite, vous pouvez continuer et écrire un getter pour cette propriété (l'implémentation utiliserait le
dispatch_once
modèle que vous avez suggéré):L'avantage de ceci est que si un utilisateur Swift va l'utiliser, il ferait quelque chose comme:
Remarque, il n'y en a pas
()
, car nous l'avons implémenté en tant que propriété. À partir de Swift 3, c'est ainsi que les singletons sont généralement accessibles. Le définir comme une propriété facilite donc cette interopérabilité.En passant, si vous regardez comment Apple définit ses singletons, voici le modèle qu'ils ont adopté, par exemple leur
NSURLSession
singleton est défini comme suit:Une autre considération d'interopérabilité Swift très mineure était le nom du singleton. Il est préférable d'incorporer le nom du type plutôt que
sharedInstance
. Par exemple, si la classe l'étaitFoo
, vous pourriez définir la propriété singleton commesharedFoo
. Ou si la classe l'étaitDatabaseManager
, vous pourriez appeler la propriétésharedManager
. Les utilisateurs de Swift pourraient alors faire:De toute évidence, si vous voulez vraiment l'utiliser
sharedInstance
, vous pouvez toujours déclarer le nom Swift si vous le souhaitez:De toute évidence, lors de l'écriture de code Objective-C, nous ne devons pas laisser l'interopérabilité Swift l'emporter sur d'autres considérations de conception, mais quand même, si nous pouvons écrire du code qui prend en charge gracieusement les deux langages, c'est préférable.
Je suis d'accord avec d'autres qui soulignent que si vous voulez que ce soit un vrai singleton où les développeurs ne peuvent pas / ne devraient pas (accidentellement) instancier leurs propres instances, le
unavailable
qualificatif est activéinit
etnew
est prudent.la source
Pour créer un singleton thread-safe, vous pouvez faire comme ceci:
et ce blog explique très bien les singletons singleton en objc / cacao
la source
la source
la source