J'aimerais stocker un tableau de références faibles dans Swift. Le tableau lui-même ne doit pas être une référence faible - ses éléments doivent l'être. Je pense que Cocoa en NSPointerArray
propose une version non sécurisée.
179
J'aimerais stocker un tableau de références faibles dans Swift. Le tableau lui-même ne doit pas être une référence faible - ses éléments doivent l'être. Je pense que Cocoa en NSPointerArray
propose une version non sécurisée.
Réponses:
Créez un wrapper générique comme:
Ajoutez des instances de cette classe à votre tableau.
Lors de la définition,
Weak
vous pouvez utiliser soitstruct
ouclass
.De plus, pour aider à récolter le contenu du tableau, vous pouvez faire quelque chose du genre:
L'utilisation de
AnyObject
ci - dessus devrait être remplacée parT
- mais je ne pense pas que le langage Swift actuel autorise une extension définie comme telle.la source
Stuff
par un protocole; voir cette question connexeVous pouvez utiliser NSHashTable avec lowObjectsHashTable.
NSHashTable<ObjectType>.weakObjectsHashTable()
Pour Swift 3:
NSHashTable<ObjectType>.weakObjects()
Référence de classe NSHashTable
la source
Any
pasAnyObject
, tels que les protocoles.MyProtocol: class
etNSHashTable<MyProtocol>.weakObjects()
. "'NSHashTable' nécessite que 'MyProtocol' soit un type de classe.Il est un peu tard pour la fête, mais essayez le mien. J'ai implémenté comme un ensemble et non un tableau.
WeakObjectSet
Usage
Attention, WeakObjectSet ne prendra pas le type String mais NSString. Parce que le type String n'est pas un AnyType. Ma version rapide est
Apple Swift version 2.2 (swiftlang-703.0.18.1 clang-703.0.29)
.Le code peut être récupéré à partir de Gist. https://gist.github.com/codelynx/30d3c42a833321f17d39
** AJOUTÉ EN NOV 2017
J'ai mis à jour le code vers Swift 4
Comme gokeji l'a mentionné, j'ai compris que NSString ne serait pas désalloué en fonction du code utilisé. Je me suis gratté la tête et j'ai écrit la classe MyString comme suit.
Puis remplacez
NSString
parMyString
comme ça. Puis étrange de dire que cela fonctionne.Ensuite, j'ai trouvé qu'une page étrange pouvait être liée à ce problème.
https://bugs.swift.org/browse/SR-5511
Il dit que le problème est,
RESOLVED
mais je me demande si cela est toujours lié à ce problème. Quoi qu'il en soit, les différences de comportement entre MyString ou NSString sont au-delà de ce contexte, mais j'apprécierais que quelqu'un trouve ce problème.la source
nil
valeurs de l'interneSet
. J'ai donc ajouté unereap()
fonction mentionnée dans la première réponse, et je me suis assuré d'appeler àreap()
chaque fois que leWeakObjectSet
est accédé.nil
plusNSString
n'est pas le cas.UnsafeMutablePointer<T>(&object)
peut changer de manière aléatoire (même chose avecwithUnsafePointer
). J'utilise maintenant une version soutenue parNSHashTable
: gist.github.com/simonseyer/cf73e733355501405982042f760d2a7d .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 plante le compilateur Swift.
Voici une version d'un conteneur d'objets faibles qui ne plante pas le compilateur publié actuel.
Vous pouvez ensuite créer un tableau de ces conteneurs:
la source
EXC_BAD_ACCESS
pour moi. Avec la classe fonctionne très bienVous pouvez le faire en créant un objet wrapper pour contenir un pointeur faible.
Et puis en les utilisant dans le tableau
la source
class
pour utiliserweak
varsprotocol Protocol : class { ... }
Qu'en est-il de l'emballage de style fonctionnel?
Appelez simplement la fermeture retournée pour vérifier que la cible est toujours en vie.
Et vous pouvez stocker ces fermetures dans un tableau.
Et vous pouvez récupérer les valeurs faiblement capturées en mappant l'appel des fermetures.
En fait, vous n'avez pas besoin d'une fonction pour faire une fermeture. Capturez simplement un objet directement.
la source
var array: [(x: Int, y: () -> T?)]
. Exactement, ce que je cherchais.let values = Array(array1.map({ $0() })) part
. Comme il ne s'agit plus d'un tableau de fermetures avec des références faibles, les valeurs seront conservées jusqu'à ce que ce tableau soit désalloué. Si j'ai raison, il est important de noter que vous ne devriez jamais conserver ce tableau commeself.items = Array(array1.map({ $0() }))
cela dépasse l'objectif.J'ai eu la même idée de créer un conteneur faible avec des génériques.
En conséquence, j'ai créé un wrapper pour
NSHashTable
:Usage:
Ce n'est pas la meilleure solution, car elle
WeakSet
peut être initialisée avec n'importe quel type, et si ce type n'est pas conforme auAnyObject
protocole, l'application plantera avec une raison détaillée. Mais je ne vois pas de meilleure solution pour le moment.La solution originale était de définir
WeakSet
de cette manière:Mais dans ce cas,
WeakSet
ne peut pas être initialisé avec le protocole:Actuellement, le code ci-dessus ne peut pas être compilé (Swift 2.1, Xcode 7.1).
C'est pourquoi j'ai abandonné la conformité
AnyObject
et ajouté des gardes supplémentaires avec desfatalError()
affirmations.la source
Détails
Solution
Option 1
Utilisation de l'option 1
Option 2
Utilisation de l'option 2
Échantillon complet
la source
protocol TP: class { } class TC { var a = WeakArray<TP>() var b = WeakObjectsArray<TP>() }
protocol TP: class { } class TC<TYPE> where TYPE: TP { var a = WeakObjectsArray<TYPE>() // Use like regular array. With any objects var weakObjectsArray = [TYPE?]() }
delegates
. Ensuite, vous auriez un certain nombre de contrôleurs de vue qui aimeraient utiliser cette fonctionnalité. Vous vous attendez à appelerMyManager.delegates.append(self)
. Mais siMyManager
est verrouillé sur un type générique, ce n'est pas très utilisable.protocol TP: class { } class MyManager { typealias Delegate = AnyObject & TP static var delegates = [Delegate?]() } class A: TP { } class B: TP { } //MyManager.delegates.append(A()) //MyManager.delegates.append(B())
L'exemple existant de WeakContainer est utile, mais il n'aide pas vraiment à utiliser des références faibles dans des conteneurs rapides existants tels que les listes et les dictionnaires.
Si vous souhaitez utiliser des méthodes List telles que contains, le WeakContainer devra implémenter Equatable. J'ai donc ajouté le code pour permettre au WeakContainer d'être égalable.
Au cas où vous voudriez utiliser le WeakContainer dans les dictionnaires, je l'ai également rendu hachable afin qu'il puisse être utilisé comme clé de dictionnaire.
Je l'ai également renommé WeakObject pour souligner que ce n'est que pour les types de classe et pour le différencier des exemples WeakContainer:
Cela vous permet de faire des choses sympas comme utiliser un dictionnaire de références faibles:
la source
Voici comment faire @ grande réponse GoZoner conforme à
Hashable
, donc il peut être indexé dans les objets Conteneur comme:Set
,Dictionary
,Array
, etc.la source
Comme cela
NSPointerArray
gère déjà la plupart de cela automatiquement, j'ai résolu le problème en créant un emballage de type sécurisé, ce qui évite une grande partie du passe-partout dans d'autres réponses:Exemple d'utilisation:
C'est plus de travail à l'avant, mais l'utilisation dans le reste de votre code est beaucoup plus propre à l'OMI. Si vous voulez le rendre plus semblable à un tableau, vous pouvez même implémenter un indice, en faire un
SequenceType
, etc. (mais mon projet n'en a besoin queappend
etforEach
je n'ai donc pas le code exact sous la main).la source
Encore une autre solution au même problème ... l'objectif de celui-ci est de stocker une référence faible à un objet, mais vous permet également de stocker une structure.
[Je ne sais pas à quel point il est utile, mais il a fallu un certain temps pour obtenir la bonne syntaxe]
la source
Vous pouvez créer un wrapper autour
Array
. Ou utilisez cette bibliothèque https://github.com/NickRybalko/WeakPointerArraylet array = WeakPointerArray<AnyObject>()
Il est de type sécurisé.la source
D'autres réponses ont couvert l'angle des génériques. Je pensais que je partagerais un code simple couvrant l'
nil
angle.Je voulais un tableau statique (lu occasionnellement) de tous les
Label
s qui existent actuellement dans l'application, mais je ne voulais pas voirnil
où se trouvaient les anciens.Rien d'extraordinaire, c'est mon code ...
la source
flatMap
au lieu defilter
&map
?Je me suis basé sur le travail de @Eonil, car j'aimais la stratégie de fermeture de liaison faible, mais je ne voulais pas utiliser un opérateur de fonction pour une variable, car cela me semblait extrêmement contre-intuitif
Ce que j'ai fait, à la place, est comme suit:
De cette façon, vous pouvez faire quelque chose comme:
la source
C'est ma solution:
-
la source
Il s'agit d'une collection de type sécurisé qui contient des conteneurs d'objets faibles. Il supprime également automatiquement nil les conteneurs / wrappers lors de l'accès.
Exemple:
La collection personnalisée https://gist.github.com/djk12587/46d85017fb3fad6946046925f36cefdc
la source
Qu'en est-il d'une approche fonctionnelle ?
C'est l'idée principale, puis ajoutez une logique de commodité pour garder une trace de ce qui se trouve dans le tableau. Par exemple, on pourrait envisager la même approche avec un dictionnaire utilisant la clé pour trouver ce qui s'y trouve.
la source