À l'aide d'un dispatch_once singleton modèle Swift
Je suis en train de mettre au point un singleton modèle pour l'utilisation de Swift. Jusqu'à présent, j'ai été en mesure d'obtenir un non-thread-safe modèle de travail:
class var sharedInstance:TPScopeManager {
get {
struct Static {
static var instance : TPScopeManager? = nil
}
if !Static.instance {
Static.instance = TPScopeManager()
}
return Static.instance!
}
}
Habillage de l'instance du singleton dans la Statique de la structure doit permettre à une instance unique qui n'entrent pas en collision avec singleton instances sans complexe de nommage schemings, et il devrait rendre les choses assez privé. De toute évidence cependant, ce modèle n'est pas thread-safe, donc j'ai essayé d'ajouter dispatch_once à l'ensemble de la chose:
class var sharedInstance:TPScopeManager {
get {
struct Static {
static var instance : TPScopeManager? = nil
static var token : dispatch_once_t = 0
}
dispatch_once(Static.token) { Static.instance = TPScopeManager() }
return Static.instance!
}
}
Mais j'obtiens une erreur du compilateur sur la dispatch_once
ligne:
Ne peut pas convertir l'expression est de type 'Void' type '()'
J'ai essayé plusieurs différentes variantes de la syntaxe, mais ils semblent tous avoir les mêmes résultats:
dispatch_once(Static.token, { Static.instance = TPScopeManager() })
Qu'est-ce que l'utilisation appropriée de dispatch_once
l'utilisation de Swift? J'ai d'abord pensé que le problème était avec le bloc en raison de la ()
dans le message d'erreur, mais plus je la regarde, plus je pense que c'est peut être une question de la dispatch_once_t
correctement défini.
C'est ce que je voulais dire. Malheureusement, nous n'avons pas encore assez d'informations sur le fonctionnement interne. Cependant, à mon humble avis, la mise en œuvre des
@lazy
doit être thread-safe.Et de cette façon, a aussi l'avantage de ne pas s'exposer à la mise en œuvre pour les prédateurs de les appelants.
Il ne semble pas que vous pouvez avoir @lazy variables de classe.
Attention! Deux choses sont à noter avec cette approche. Tout d'abord, toutes les classes qui héritent de ce qui aura pour remplacer le sharedInstance de la propriété.
Static.instance = TPScopeManager()
forces du type d'instance. Si vous utilisez quelque chose comme Static.instance = self()
avec un initialiseur, le type approprié de la classe sera généré. Même si, et c'est la chose importante à noter, qu'une seule fois pour toutes les instances de la hiérarchie! Premier type d'initialiser le type est définie pour toutes les instances. Je ne pense pas que l'objective-c se comportaient de la même.OriginalL'auteur David Berry | 2014-06-03
Vous devez vous connecter pour publier un commentaire.
tl;dr: Utiliser le constante de classe approche si vous utilisez Swift 1.2 ou supérieur et de la imbriquée struct approche si vous avez besoin de support des versions antérieures.
De mon expérience avec Swift il y a trois méthodes pour implémenter le pattern Singleton qui prennent en charge l'initialisation tardive et du fil de sécurité.
Constante de classe
Cette approche prend en charge l'initialisation tardive parce que Swift paresseusement initialise les constantes de classe (et variables), et est thread-safe par la définition de
let
. C'est maintenant officiellement recommandé pour instancier un singleton.Des constantes de classe ont été introduites dans Swift 1.2. Si vous avez besoin de l'appui d'une version antérieure de Swift, utilisez le imbriquée struct approche ci-dessous ou à une constante globale.
Imbriquée struct
Nous voici à l'aide de la constante statique d'un imbriquée struct comme une constante de classe. C'est une solution de contournement pour le manque de classe statique constantes dans Swift 1.1 et versions antérieures, et travaille toujours comme une solution de contournement pour le manque de statique des constantes et des variables dans les fonctions.
dispatch_once
La traditionnelle Objective-C approche porté à Swift. Je suis assez certain que il n'y a aucun avantage sur le imbriquée struct approche, mais je suis en train de mettre ici de toute façon comme je l'ai trouver les différences dans la syntaxe intéressant.
Voir ce GitHub projet pour les tests unitaires.
Les constantes sont thread-safe dans toutes les langues que je connais.
Je suppose que vous parlez de la dernière approche. Je vais me citer: "je dirais qu'il n'est plus nécessaire pour utiliser cette approche, mais je suis en train de mettre ici de toute façon comme je l'ai trouver les différences dans la syntaxe intéressant."
Devrait
init
également être déclaréprivate
de garantir une et une seule instance de l'objet ne sera jamais exister tout au long de l'application de la durée de vie?Dans la "constante de Classe" approche, je vous suggère de (a) déclaration de la classe à être
final
afin de ne pas sous-classe; et (b) le fait de déclarer lainit
méthode àprivate
de sorte que vous ne pouvez pas accidentellement instancier un autre exemple quelque part.OriginalL'auteur hpique
Puisque Apple a désormais clair que static struct variables sont initialisées à la fois paresseux et enveloppé dans dispatch_once (voir la note à la fin du post), je pense que ma solution finale va être:
Cela prend avantage de l'automatique paresseux, thread-safe initialisation static struct éléments en toute sécurité, se cache la mise en œuvre effective de la consommation, permet de tout de façon compacte compartimentée pour la lisibilité, et élimine visible variable globale.
Apple a précisé que paresseux initialiseur sont thread-safe, il n'y a pas besoin de
dispatch_once
ou des protections similairesDe ici
Je voudrais ajouter qu'une bonne pratique serait de déclarer l'initialiseur privé:
private init() {}
, afin de mieux appuyer le fait que cette classe n'est pas destiné à être extérieur instancié.donc static struct var initialisation est paresseux et thread-safe, si ce static struct var est un dictionnaire pour multitons, alors nous avons pour synchroniser manuellement/file d'attente des appels pour chaque accès, d'un droit?
Si je comprends votre question correctement, un dictionnaire et des accès à des tableaux ne sont pas intrinsèquement thread-safe, vous aurez besoin d'utiliser une certaine forme de la synchronisation des threads.
Comment dois-je appeler une fonction à l'intérieur de cette classe singleton? J'ai besoin d'une fonction qui doit être appelée sur le premier appel de myClass.sharedInstance.
OriginalL'auteur
Pour Swift 1.2 et au-delà:
Avec une preuve de la justesse (tout le crédit va ici), il y a peu de raison maintenant utiliser une des méthodes précédentes pour les singletons.
Mise à jour: C'est maintenant la officiel façon de définir les singletons comme décrit dans la officiel docs!
Que pour des questions sur l'utilisation de
static
vsclass
.static
devrait être le seul à utiliser même lorsqueclass
variables deviennent disponibles. Les Singletons sont pas destinés à être sous-classé, car le résultat serait dans plusieurs instances de la base de singleton. À l'aide destatic
applique dans ce une belle, Swifty.Pour Swift 1.0 et 1.1:
Avec les changements récents de la Swift, la plupart des nouvelles méthodes de contrôle d'accès, je suis maintenant penché vers le moyen le plus propre d'utiliser une variable globale pour les singletons.
Comme mentionné dans la Swift article du blog de ici:
Cette façon de créer un singleton est thread-safe, rapide, paresseux, et également relié à ObjC gratuitement.
sinon, le comportement n'est pas défini, il est juste cassé dans une bien défini: le bloc sera toujours exécuté.
La documentation indique qu'il n'est pas défini. Le comportement actuel est donc fortuite.
C'est une chose étrange à dire. Si la documentation appelle "undefined" cela signifie simplement que celui qui a écrit le code ne fait pas de promesses à ce qu'il fait. Il n'a rien à voir avec le code de savoir si la variable est statique. Cela signifie simplement que le courant (ou apparent) le comportement ne peut pas être invoquée.
Vous pouvez ajouter
private init() {}
comme initiateur de"SingletonClass
. pour éviter instancier à partir de l'extérieur.OriginalL'auteur Jack
Swift 1.2 ou ultérieure prend désormais en charge statique des variables/constantes dans les classes. De sorte que vous pouvez simplement utiliser une constante statique:
OriginalL'auteur Florian
Il y a une meilleure façon de le faire. Vous pouvez déclarer une variable globale dans votre classe au-dessus de la classe decleration comme
- Ce juste des appels de votre init par défaut ou n'importe quel init et les variables globales sont dispatch_once par défaut dans Swift. Alors dans quelle catégorie vous souhaitez obtenir une référence, vous faites simplement ceci:
Donc, fondamentalement, vous pouvez vous débarrasser de la totalité du bloc de l'instance partagée code.
peut-être pourrait être un de laisser, j'ai testé uniquement avec une var.
J'aime cette réponse, cependant j'ai besoin d'accéder à ce (Singleton) à partir de l'Interface Builder. Aucune idée sur comment pourrais-je accéder à ce tpScopeManagerSharedInstance de l'intérieur de l'IB?. Merci.-
C'est ma façon préférée d'avoir un singleton. Il a toutes les fonctionnalités habituelles (thread-safety & paresseux instanciation) et il prend en charge un très léger syntaxe: pas besoin d'écrire
TPScopeManager.sharedInstance.doIt()
tout le temps, juste le nom de votre classeTPScopeManagerClass
, ont cette déclaration suivante à la classepublic let TPScopeManager = TPScopeManagerClass()
, et lors de l'utilisation il suffit d'écrireTPScopeManager.doIt()
. Très propre!!Il n'y a rien ici pour éviter de créer de nouvelles instances de
TPScopeManager
, et il est donc ce n'est pas un singleton, par définition.OriginalL'auteur Kris Gellci
Swift singletons sont exposés dans le Cacao cadres des fonctions de classe, par exemple
NSFileManager.defaultManager()
,NSNotificationCenter.defaultCenter()
, alors je pense qu'il est plus logique comme une fonction de classe à un miroir de ce comportement, plutôt que d'une variable de classe que d'autres solutions, par exempleRécupérer le singleton via
MyClass.sharedInstance()
.la variable globale doit être modifié pour une variable de classe via une statique à l'intérieur de la classe.
lorsqu'une variable est marqué comme privé, mais à l'extérieur d'une classe, il n'est pas global mais limitée uniquement pour le fichier c'est dans. Un statique à l'intérieur de la classe du travail à peu près la même, mais j'ai mis à jour la réponse à l'utilisation de la statique comme vous l'avez suggéré, comme il meilleurs groupes de la variable de la classe, si vous arrive d'utiliser plusieurs classes dans le fichier.
"Swift Singletons sont exposés dans le cacao cadres des fonctions de classe" ... Pas dans Swift 3. Ils sont maintenant généralement
static
propriétés.OriginalL'auteur Ryan
Par la La documentation d'Apple, il a été répété à plusieurs reprises que la meilleure façon de le faire dans Swift est statique type de propriété:
Toutefois, si vous êtes à la recherche d'un moyen d'effectuer des réglages supplémentaires au-delà d'un simple appel du constructeur, le secret est d'utiliser un immédiatement appelé fermeture:
Ceci est garanti pour être thread-safe et initialisées qu'une seule fois.
Vous ne pouvez pas, et en général ne le sont pas.
OriginalL'auteur Adrian Macneil
Swift 4+
devraient-ils être privés de remplacer init() {}
OriginalL'auteur Adam Smaka
À la recherche d'Apple est un exemple de code, je suis tombé sur ce modèle. Je ne suis pas sûr de la façon de Swift traite de la statique, mais ce serait thread-safe en C#. - Je inclure à la fois la propriété et la méthode pour Objective-C interop.
malheureusement, la statique, seul le travail à l'intérieur de leurs structures, c'est pourquoi ce modèle.
Mon intention est que nous n'avons pas à utiliser
dispatch_once
animaux. Je suis de paris votre style. 🙂J'aime bien cette solution, mais est-ce "thread-safe"?
N'est-ce pas
class
dans une déclaration de classe, l'équivalent destatic
dans une struct déclaration?OriginalL'auteur user2485100
En bref,
Vous voudrez peut-être lire Fichiers et d'Initialisation
OriginalL'auteur onmyway133
Si vous prévoyez sur l'utilisation de votre Swift classe singleton en Objective-C, ce programme d'installation du compilateur de générer de l'Objectif-C-comme en-tête(s):
Puis en Objective-C, classe, vous pouvez appeler votre singleton de la façon dont vous l'avez fait dans la pré-Swift jours:
Ce n'est que mon simple mise en œuvre.
NSFileManager.defaultManager()
, mais utilise toujours le paresseux thread-safe membre statique des mécanismes de Swift.Cacao en général met en œuvre ces propriétés statiques, de nos jours, non pas comme des fonctions de classe.
Je suis conscient de cela, mon commentaire est de plus de 2 ans. Merci pour la mention.
OriginalL'auteur Michael
Première solution
Plus loin dans votre code:
Deuxième solution
Et plus loin dans votre code, vous serez en mesure de garder des accolades pour moins de confusion:
OriginalL'auteur Nicolas Manzini
Ensuite l'appeler;
init
commeprivate
, mais aussi pour faire lesharedMyModel
commefinal
! Pour le plaisir des futurs lecteurs, dans Swift 3, nous pourrions être enclins à renommersharedMyModel
être simplementshared
.C'est la seule réponse correcte, sauf que le remplacement et l'appel à super.init sont erronées et ne seront même pas compiler.
OriginalL'auteur Kemal Can Kaynak
Utilisation:
Comment utiliser:
Autres que de ne pas avoir une variable globale. 🙂
non, exactement comme l'une de mes premières tentatives. Regardez l'historique d'édition.
OriginalL'auteur Kingiol
La meilleure approche dans le Swift 1.2 ci-dessus est une ligne de singleton, -
De savoir plus de détails sur cette approche, vous pouvez visiter ce lien.
NSObject
sous-classe?. En dehors de cela, ce qui semble être essentiellement le même que stackoverflow.com/a/28436202/1187415.OriginalL'auteur CodeCracker
Je dirais un Enum, comme vous le feriez utiliser en Java, par exemple:
Pourriez-vous élaborer sur cette réponse? Il n'est pas clair pour moi, où Singleton est instancié à partir de cet extrait
Je n'ai pas de développeur d'Apple de connexion, donc pas de swift et donc je ne peux pas répondre lors de l'initialisation se produit. En Java, il est sur la première utilisation. Vous pourriez peut-être essayer avec une impression sur l'initialisation et de voir si l'impression se produit lors du lancement ou après l'accès. Il dépendra de la façon dont enum est mis en œuvre par le compilateur.
Apple vient de clarifier la manière dont cela fonctionne, voir developer.apple.com/swift/blog/?id=7. Dans ce qu'ils disent "exécuter l'initialiseur mondiale, la première fois qu'il est référencé, similaire à Java" et en particulier. Ils disent aussi que sous les couvertures qu'ils sont à l'aide de "dispatch_once pour s'assurer que l'initialisation est atomique". Donc enum est presque certainement la voie à suivre, sauf si vous avez un peu de fantaisie init à faire, puis une private static laissez est la solution.
OriginalL'auteur Howard Lovatt
D'Apple Docs (Swift 3.0.1),
OriginalL'auteur sleepwalkerfx
Juste pour référence, voici un exemple de Singleton mise en œuvre de Jack Wu/hpique Imbriqués Struct mise en œuvre. La mise en œuvre montre aussi comment l'archivage, ainsi que certaines fonctions d'accompagnement. Je ne pouvais pas trouver cette complète d'un exemple, donc j'espère que cela aide quelqu'un!
Et si vous ne le reconnaissent pas certaines de ces fonctions, voici un peu de vie Swift utilitaire de fichier j'ai été en utilisant:
OriginalL'auteur SchoonSauce
La seule bonne approche est ci-dessous
Pour Accéder À
Raisons:
static let sharedInstance = Singleton()
si vous ne voulez pas faire de configuration puis ce que vous dites est juste.
OriginalL'auteur applefreak
Je préfère cette mise en œuvre:
OriginalL'auteur Viktor Radchenko
Ma façon de mise en œuvre de Swift...
ConfigurationManager.swift
Accéder à la globalDic à partir de n'importe quel écran de l'application ci-dessous.
Lire:
Écrire:
OriginalL'auteur user2737730
Après avoir vu David de la mise en œuvre, il semble qu'il n'y a pas besoin d'avoir une classe singleton fonction instanceMethod depuis
let
est en train de faire à peu près la même chose qu'un sharedInstance méthode de classe. Tout ce que vous devez faire est de le déclarer comme une constante globale et que serait-il.OriginalL'auteur Essa A. Haddad
dispatch_once
depuis l'initialisation d'une variable statique est paresseux et automatiquement protégée pardispatch_once
effectivement d'Apple recommande l'utilisation de la statique au lieu de dispatch_once pour cette raison.OriginalL'auteur DD.amor
Rapide à réaliser singleton dans le passé, n'est rien de plus que de trois façons: les variables globales, variables internes et dispatch_once façons.
Voici deux bonnes singleton.(remarque: quel que soit le type de l'écriture doit prêter attention à la méthode init () de la privatisation.Parce que dans Swift, tous le constructeur de l'objet par défaut est public, doit être réécrit init peut être transformé en privé, empêcher d'autres objets de cette classe '()' par défaut initialisation de la méthode pour créer l'objet.)
Méthode 1:
Méthode 2:
OriginalL'auteur Tim
Je suis tombé sur ça, mais j'ai tenu mon singleton pour permettre à l'héritage, et aucune de ces solutions réellement permis.
Alors je suis venu avec cette:
Le problème avec ce sale première approche est que je ne peut pas garantir que les sous-classes de mettre en œuvre les dispatch_once_t et assurez-vous que sharedInstanceVar n'est modifié qu'une fois par classe...
Je vais essayer d'affiner encore ce que cela, mais il serait intéressant de voir si quelqu'un a des sentiments forts à l'encontre de ce (outre le fait que c'est verbeux et nécessite de mettre à jour manuellement).
OriginalL'auteur RicardoDuarte
C'est le plus simple avec thread-safe capacités. Aucun autre thread ne peut accéder au même objet singleton, même si elles le veulent. Swift 3/4
OriginalL'auteur Abhishek Biswas
utiliser une variable statique et privé de l'initialiseur de créer une classe singleton.
OriginalL'auteur Prashant Bhayani
C'est mon œuvre. Il empêche également le programmeur de la création d'une nouvelle instance:
private init
a été déjà suggéré ici: stackoverflow.com/a/28436202/1187415.OriginalL'auteur Yedidya Reiss
OriginalL'auteur Mike
J'ai tendance à utiliser la syntaxe suivante la plus complète:
Cela fonctionne à partir de Swift 1.2 jusqu'à 4, et dispose de plusieurs vertus:
Singleton.instance
OriginalL'auteur Gonzalo Durañona