Comment dois-je déclarer un tableau de références faibles dans Swift?
J'aimerais stocker un tableau de références faibles en Swift. Le tableau lui-même ne devrait pas être une référence faible - ses éléments doivent être. Je pense que le Cacao NSPointerArray
offre un non-typesafe version de ce.
- Qu'en faire un objet de conteneur faiblement fait référence à un autre objet, puis de faire un tableau de ceux-là? (Si vous n'obtenez pas une meilleure réponse)
- pourquoi n'utilisez-vous pas un NSPointerArray ?
- C'est un vieux obj-c solution 🙂 Pour en faire Swifty, il doit être un objet générique! 🙂 Cependant, le vrai problème est de savoir comment obtenir les objets retirés du tableau lorsque l'objet référencé est libéré.
- Bon, je préfère quelque chose avec un type paramétré. Je suppose que je pourrais faire un wrapper paramétrable autour de NSPointerArray, mais je voulais voir si il y avait des solutions de rechange.
- Avez-vous essayé
Array<weak AnyObject>
? - Tout comme une autre option, NSHashTable existe. En gros, c'est un NSSet qui vous permet de spécifier la façon dont il doit faire référence aux objets qu'il contient.
- oui, vous aurez à utiliser un accès indirect... comme si (nil) { retirer la poignée du tableau }
- Ce doit être une langue bug que toutes les solutions proposées atteindre le résultat immédiat grâce à l'encapsulation et de briser la sémantique du type. Par exemple, un tableau de protocole de références perdre leur protocole d'identité, ce qui signifie qu'ils ne peuvent pas être exposés à Interface Builder via IBOutlet.
Vous devez vous connecter pour publier un commentaire.
Créer un wrapper générique comme:
Ajouter des instances de cette classe à votre ensemble.
Lors de la définition de
Weak
vous pouvez utiliserstruct
ouclass
.Aussi, pour l'aider à récolter le contenu du tableau, vous pouvez faire quelque chose le long des lignes de:
L'utilisation de
AnyObject
ci-dessus doit être remplacé parT
- mais je ne pense pas que la Swift actuel de la langue permet une extension définie comme telle.if let value = array[index].value? { ... }
. Ou définirclass WeakArray : Array { ... }
count
?Stuff
par un protocole; voir cette question connexeAnyObject
ou:class
types. Vous pouvez observer ce en essayant de déclarerweak var value : <type>
avec différents types de - la Swift compilateur de limiter votre choix à la classe de types".T
est une classe de protocoleVous pouvez utiliser le NSHashTable avec weakObjectsHashTable.
NSHashTable.weakObjectsHashTable()
Pour Swift 3:
NSHashTable.weakObjects()
NSHashTable De Référence De Classe
Any
mais pasAnyObject
, tels que des protocoles.MyProtocol: class
etNSHashTable<MyProtocol>.weakObjects()
. "'NSHashTable' exige que les 'MyProtocol' être un type de classe.Ce n'est pas ma solution. Je l'ai trouvé sur les Forums des Développeurs Apple.
@GoZoner a une bonne réponse, mais il se bloque, la Swift compilateur.
Voici une version de la faiblesse de l'-conteneur de l'objet ne tombe pas en panne le courant publié compilateur.
Vous pouvez ensuite créer un tableau de ces conteneurs:
EXC_BAD_ACCESS
pour moi. Avec la classe fonctionne très bienC'est une sorte de fin de partie, mais essayez de la mine. J'ai mis en œuvre comme un Ensemble pas un Tableau.
WeakObjectSet
Utilisation
Attention, WeakObjectSet ne veut pas prendre de type String mais NSString. Parce que, type de Chaîne n'est pas une AnyType. Mon swift version est
Apple Swift version 2.2 (swiftlang-703.0.18.1 clang-703.0.29)
.Code peut être saisi à partir de Gist.
https://gist.github.com/codelynx/30d3c42a833321f17d39
** AJOUT DE NOV.2017
J'ai mis à jour le code Swift 4
Comme gokeji mentionné, j'ai compris NSString ne désallouées basé sur le code de la consommation.
Je me grattais la tête et j'ai écrit MyString classe comme suit.
Puis remplacer
NSString
avecMyString
comme ça. Puis, chose étrange à dire, il fonctionne.Puis j'ai trouvé une étrange page peut être lié à ce problème.
https://bugs.swift.org/browse/SR-5511
Il affirme que le problème est
RESOLVED
mais je me demande si c'est toujours lié à ce problème.De toute façon, les différences de Comportement entre MyString ou NSString sont au-delà de ce contexte, mais j'apprécierais si quelqu'un a trouvé cette question.
nil
valeurs de l'interneSet
. J'ai donc ajouté unreap()
fonction mentionné dans la réponse sommet, et fait en sorte d'appelreap()
chaque fois que leWeakObjectSet
est accessible.nil
plusNSString
ne l'est pas.WeakObjectSet class
. La façon dont je l'utilise, j'ai la faiblesse des références à UIKit composants tels queUITableViews
,UICollectionViews
. Ces composants de mettre en œuvre une classe de protocoleA
, et puis dans ma classe, je déclare une faible définir comme suit:var set = WeakObjectSet<A>()
. Lorsque le ViewController rejette le long de ses points de vue,set
se comporte correctement (les vues sont partis à partir de l'ensemble), mais la mémoire de l'instrument indique une fuite auspecialized WeakObject.init(object:)
.UnsafeMutablePointer<T>(&object)
peut changer de façon aléatoire (même avecwithUnsafePointer
). Maintenant j'utilise une version soutenue par uneNSHashTable
: gist.github.com/simonseyer/cf73e733355501405982042f760d2a7d.Vous pouvez le faire en créant un objet wrapper de tenir une faible pointeur.
Et puis, à l'aide de ces dans le tableau
class
à utiliserweak
varsprotocol Protocol : class { ... }
Foo
est un protocole. Si vous utilisez Swift 2, un bug conduit à des erreurs de compilation pour certains protocoles, cependant. Voir cette question pour plus de détails et une solution de contournement.J'ai eu la même idée pour créer de faibles conteneur avec des génériques.
Comme résultat, j'ai créé wrapper pour
NSHashTable
:Utilisation:
Ce n'est pas la meilleure solution, parce
WeakSet
peut être initialisée avec n'importe quel type, et si ce type n'est pas conforme àAnyObject
protocole de l'app crash détaillée de la raison. Mais je ne vois pas de meilleure solution actuellement.Solution originale était de définir
WeakSet
de cette façon:Mais dans ce cas
WeakSet
ne peut pas être initialisé avec le protocole:Actuellement de code ci-dessus ne peut pas être compilé (Swift 2.1, Xcode 7.1).
C'est pourquoi j'ai laissé tomber conforme à
AnyObject
et ajouté des gardes avecfatalError()
affirmations.Comment au sujet de style fonctionnel wrapper?
Appelez simplement retourné la fermeture de vérifier la cible est toujours en vie.
Et vous pouvez stocker ces fermetures dans un tableau.
Et vous pouvez récupérer les faibles valeurs saisies par la cartographie de l'appel de la fermeture.
var array: [(x: Int, y: () -> T?)]
. Exactement ce que je cherchais.L'exemple de la WeakContainer est utile, mais cela n'aide pas vraiment une utilisation faible des références dans de swift en récipients tels que les Listes et les Dictionnaires.
Si vous souhaitez utiliser la Liste des méthodes telles que contient, puis le WeakContainer aurez besoin de mettre en œuvre Equatable. J'ai donc ajouté du code pour permettre la WeakContainer être equatable.
Dans le cas où vous voulez utiliser l'WeakContainer dans les dictionnaires, j'ai aussi fait il hashable de sorte qu'il peut être utilisé comme dictionnaire clés.
J'ai aussi renommé WeakObject de souligner que c'est seulement pour les types de classe et de la différencier de la WeakContainer exemples:
Cela vous permet de faire des trucs cool comme utiliser un Dictionnaire de références faibles:
Détails
Solution
Utilisation
Totalité de l'échantillon
Voici comment faire @GoZoner de la grande réponse conforme à
Hashable
, de sorte qu'il peut être indexé dans le Conteneur d'objets comme:Set
,Dictionary
,Array
, etc.D'autres réponses que nous avons couvert les génériques de l'angle. J'ai pensé partager un code simple couvrant la
nil
angle.Je voulais un tableau statique (lire de temps en temps) de tous les
Label
s qui existent actuellement dans l'application, mais ne veulent pas voirnil
's où les anciens que ceux utilisés pour être.Rien de compliqué, c'est mon code...
flatMap
au lieu defilter
&map
?Encore une autre solution pour le même problème... le foyer de celui-ci est sur le stockage à un faible référence à un objet, mais vous permettant de stocker une structure trop.
[Je ne suis pas sûr combien il est utile, mais il a pris un certain temps pour obtenir la syntaxe de droite]
Depuis
NSPointerArray
déjà gère la plupart de ce automatiquement, j'ai résolu le problème en faisant un type sûr de wrapper pour elle, ce qui évite beaucoup de la réutilisable dans d'autres réponses:Exemple d'utilisation:
C'est plus de travail à l'avant, mais l'usage dans le reste de votre code est beaucoup plus propre de l'OMI. Si vous voulez le rendre plus semblable au tableau, vous pouvez même mettre en place subscripting, faire un
SequenceType
, etc. (mais mon projet a besoin seulement deappend
etforEach
donc je n'ai pas le code exact sous la main).Vous pouvez créer un wrapper autour de
Array
. Ou de l'utilisation de cette bibliothèque https://github.com/NickRybalko/WeakPointerArraylet array = WeakPointerArray<AnyObject>()
Il est de type sécurisé.
Je me suis basé sur ce @Eonil 's de travail, car j'adore la fermeture de la faiblesse de l'affectation de la stratégie, mais je n'ai pas envie d'utiliser un opérateur de fonction d'une variable, depuis qu'il a senti extrêmement contre-intuitif
Ce que j'ai fait, au contraire, est comme suit:
De cette façon, vous pouvez faire quelque chose comme:
Ce ma solution:
--