Comment puis-je déclarer un tableau de références faibles dans Swift?

Je voudrais stocker un tableau de références faibles dans Swift. Le tableau lui-même ne devrait pas être une référence faible - ses éléments doivent être. Je pense que Cocoa NSPointerArray offre une version non-typesafe de ceci.

158
demandé sur János 2014-06-09 23:34:30

15 réponses

Créer un wrapper générique comme:

class Weak<T: AnyObject> {
  weak var value : T?
  init (value: T) {
    self.value = value
  }
}

Ajoutez des instances de cette classe à votre tableau.

class Stuff {}
var weakly : [Weak<Stuff>] = [Weak(value: Stuff()), Weak(value: Stuff())]

Lors de la définition de Weak, vous pouvez utiliser soit struct ou class.

Aussi, pour aider à récolter le contenu du tableau, vous pouvez faire quelque chose du genre:

extension Array where Element:Weak<AnyObject> {
  mutating func reap () {
    self = self.filter { nil != $0.value }
  }
}

L'utilisation de AnyObject ci - dessus devrait être remplacée par T - mais je ne pense pas que le langage Swift actuel permette une extension définie comme telle.

132
répondu GoZoner 2016-09-16 21:42:01

Vous pouvez utiliser NSHashTable avec weakObjectsHashTable. NSHashTable.weakObjectsHashTable()

Pour Swift 3: NSHashTable.weakObjects()

Référence De Classe NSHashTable

Disponible dans OS X v10. 5 et versions ultérieures.

Disponible dans iOS 6.0 et versions ultérieures.

36
répondu Thierry 2017-02-13 16:11:26

Ce n'est pas ma solution. Je l'ai trouvé sur les Forums de développeurs Apple .

@GoZoner a une bonne réponse, mais il bloque le compilateur Swift.

Voici une version d'un conteneur d'objets faibles qui ne plante pas le compilateur publié en cours.

struct WeakContainer<T where T: AnyObject> {
    weak var _value : T?

    init (value: T) {
        _value = value
    }

    func get() -> T? {
        return _value
    }
}

Vous pouvez ensuite créer un tableau de ces conteneurs:

let myArray: Array<WeakContainer<MyClass>> = [myObject1, myObject2]
10
répondu rjkaplan 2014-06-10 08:49:19

Il est un peu tard pour la fête, mais essayez le mien. J'ai implémenté comme un ensemble pas un tableau.

WeakObjectSet

class WeakObject<T: AnyObject>: Equatable, Hashable {
    weak var object: T?
    init(object: T) {
        self.object = object
    }

    var hashValue: Int {
        if let object = self.object { return unsafeAddressOf(object).hashValue }
        else { return 0 }
    }
}

func == <T> (lhs: WeakObject<T>, rhs: WeakObject<T>) -> Bool {
    return lhs.object === rhs.object
}


class WeakObjectSet<T: AnyObject> {
    var objects: Set<WeakObject<T>>

    init() {
        self.objects = Set<WeakObject<T>>([])
    }

    init(objects: [T]) {
        self.objects = Set<WeakObject<T>>(objects.map { WeakObject(object: $0) })
    }

    var allObjects: [T] {
        return objects.flatMap { $0.object }
    }

    func contains(object: T) -> Bool {
        return self.objects.contains(WeakObject(object: object))
    }

    func addObject(object: T) {
        self.objects.unionInPlace([WeakObject(object: object)])
    }

    func addObjects(objects: [T]) {
        self.objects.unionInPlace(objects.map { WeakObject(object: $0) })
    }
}

Utilisation

var alice: NSString? = "Alice"
var bob: NSString? = "Bob"
var cathline: NSString? = "Cathline"

var persons = WeakObjectSet<NSString>()
persons.addObject(bob!)
print(persons.allObjects) // [Bob]

persons.addObject(bob!)
print(persons.allObjects) // [Bob]

persons.addObjects([alice!, cathline!])
print(persons.allObjects) // [Alice, Cathline, Bob]

alice = nil
print(persons.allObjects) // [Cathline, Bob]

bob = nil
print(persons.allObjects) // [Cathline]

Méfiez-vous que WeakObjectSet ne prendra pas le type de chaîne mais NSString. Parce que, le type de chaîne n'est pas un AnyType. Ma version swift est Apple Swift version 2.2 (swiftlang-703.0.18.1 clang-703.0.29).

Le Code peut être saisi à partir de Gist. https://gist.github.com/codelynx/30d3c42a833321f17d39

* * AJOUTÉ EN NOV.2017

J'ai mis à jour le code à Swift 4

// Swift 4, Xcode Version 9.1 (9B55)

class WeakObject<T: AnyObject>: Equatable, Hashable {
    weak var object: T?
    init(object: T) {
        self.object = object
    }

    var hashValue: Int {
        if var object = object { return UnsafeMutablePointer<T>(&object).hashValue }
        return 0
    }

    static func == (lhs: WeakObject<T>, rhs: WeakObject<T>) -> Bool {
        return lhs.object === rhs.object
    }
}

class WeakObjectSet<T: AnyObject> {
    var objects: Set<WeakObject<T>>

    init() {
        self.objects = Set<WeakObject<T>>([])
    }

    init(objects: [T]) {
        self.objects = Set<WeakObject<T>>(objects.map { WeakObject(object: $0) })
    }

    var allObjects: [T] {
        return objects.flatMap { $0.object }
    }

    func contains(_ object: T) -> Bool {
        return self.objects.contains(WeakObject(object: object))
    }

    func addObject(_ object: T) {
        self.objects.formUnion([WeakObject(object: object)])
    }

    func addObjects(_ objects: [T]) {
        self.objects.formUnion(objects.map { WeakObject(object: $0) })
    }
}

Comme gokeji a mentionné, j'ai compris que NSString ne sera pas désalloué en fonction du code utilisé. Je me suis gratté la tête et j'ai écrit MyString classe comme suit.

// typealias MyString = NSString
class MyString: CustomStringConvertible {
    var string: String
    init(string: String) {
        self.string = string
    }
    deinit {
        print("relasing: \(string)")
    }
    var description: String {
        return self.string
    }
}

, Puis remplacez NSString avec MyString comme ceci. Alors étrange de dire que cela fonctionne.

var alice: MyString? = MyString(string: "Alice")
var bob: MyString? = MyString(string: "Bob")
var cathline: MyString? = MyString(string: "Cathline")

var persons = WeakObjectSet<MyString>()

persons.addObject(bob!)
print(persons.allObjects) // [Bob]

persons.addObject(bob!)
print(persons.allObjects) // [Bob]

persons.addObjects([alice!, cathline!])
print(persons.allObjects) // [Alice, Cathline, Bob]

alice = nil
print(persons.allObjects) // [Cathline, Bob]

bob = nil
print(persons.allObjects) // [Cathline]

Ensuite, j'ai trouvé une page étrange peut être liée à ce problème.

La référence faible conserve NSString désalloué (xC9 + iOS Sim uniquement)

Https://bugs.swift.org/browse/SR-5511

Il dit le 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 si quelqu'un a compris ce problème.

9
répondu Kaz Yoshikawa 2017-11-14 05:36:25

Vous pouvez le faire en créant un objet wrapper pour contenir un pointeur faible.

struct WeakThing<T: AnyObject> {
  weak var value: T?
  init (value: T) {
    self.value = value
  }
}

Puis en les utilisant dans le tableau

var weakThings = WeakThing<Foo>[]()
8
répondu Joshua Weinberg 2014-06-09 20:09:25

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éé wrapper pour NSHashTable:

class WeakSet<ObjectType>: SequenceType {

    var count: Int {
        return weakStorage.count
    }

    private let weakStorage = NSHashTable.weakObjectsHashTable()

    func addObject(object: ObjectType) {
        guard object is AnyObject else { fatalError("Object (\(object)) should be subclass of AnyObject") }
        weakStorage.addObject(object as? AnyObject)
    }

    func removeObject(object: ObjectType) {
        guard object is AnyObject else { fatalError("Object (\(object)) should be subclass of AnyObject") }
        weakStorage.removeObject(object as? AnyObject)
    }

    func removeAllObjects() {
        weakStorage.removeAllObjects()
    }

    func containsObject(object: ObjectType) -> Bool {
        guard object is AnyObject else { fatalError("Object (\(object)) should be subclass of AnyObject") }
        return weakStorage.containsObject(object as? AnyObject)
    }

    func generate() -> AnyGenerator<ObjectType> {
        let enumerator = weakStorage.objectEnumerator()
        return anyGenerator {
            return enumerator.nextObject() as! ObjectType?
        }
    }
}

Utilisation:

protocol MyDelegate : AnyObject {
    func doWork()
}

class MyClass: AnyObject, MyDelegate {
    fun doWork() {
        // Do delegated work.
    }
}

var delegates = WeakSet<MyDelegate>()
delegates.addObject(MyClass())

for delegate in delegates {
    delegate.doWork()
}

Ce n'est pas la meilleure solution, car WeakSet peut être initialisé avec n'importe quel type, et si ce type n'est pas conforme au Protocole AnyObject, l'application se bloque avec une raison détaillée. Mais je ne vois pas de meilleure solution en ce moment.

Solution Originale était de définir WeakSet de cette façon:

class WeakSet<ObjectType: AnyObject>: SequenceType {}

, Mais dans ce cas - WeakSet impossible d'initialiser avec le protocole:

protocol MyDelegate : AnyObject {
    func doWork()
}

let weakSet = WeakSet<MyDelegate>()

Actuellement, le code ci-dessus ne peut pas être compilé (Swift 2.1, Xcode 7.1).
C'est pourquoi j'ai abandonné me conformer à AnyObject et ajouté des gardes supplémentaires avec des assertions fatalError().

7
répondu Vlad Papko 2015-11-14 05:44:37

Que diriez-vous d'un wrapper de style fonctionnel?

class Class1 {}

func captureWeakly<T> (_ target:T) -> (() -> T?) where T: AnyObject {
    return { [weak target] in
        return target
    }
}

let obj1 = Class1()
let obj2 = Class1()
let obj3 = Class1()
let captured1 = captureWeakly(obj1)
let captured2 = captureWeakly(obj2)
let captured3 = captureWeakly(obj3)

Appelez simplement la fermeture retournée pour vérifier que la cible est toujours vivante.

let isAlive = captured1() != nil
let theValue = captured1()!

Et vous pouvez stocker ces fermetures dans un tableau.

let array1 = Array<() -> (Class1?)>([captured1, captured2, captured3])

Et vous pouvez récupérer les valeurs faiblement capturées en mappant l'appel des fermetures.

let values = Array(array1.map({ $0() }))
7
répondu Eonil 2016-09-25 13:23:25

L'exemple existant de WeakContainer est utile, mais il n'aide pas vraiment à utiliser des références faibles dans des conteneurs swift existants tels que des listes et des 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 souhaiteriez utiliser le WeakContainer dans les dictionnaires, Je l'ai également rendu hashable afin qu'il puisse être utilisé comme dictionnaire touches.

Je l'ai également renommé en WeakObject pour souligner que ce n'est que pour les types de classe et pour le différencier des exemples WeakContainer:

struct WeakObject<TYPE where TYPE:AnyObject> : Equatable, Hashable
{
    weak var _value : TYPE?
    let _originalHashValue : Int

    init (value: TYPE)
    {
        _value = value

        // We keep around the original hash value so that we can return it to represent this
        // object even if the value became Nil out from under us because the object went away.
        _originalHashValue = ObjectIdentifier(value).hashValue
    }

    var value : TYPE?
    {
        return _value
    }

    var hashValue: Int
    {
        return _originalHashValue
    }
}

func ==<T>(lhs: WeakObject<T>, rhs: WeakObject<T>) -> Bool
{
    if lhs.value == nil  &&  rhs.value == nil {
        return true
    }
    else if lhs.value == nil  ||  rhs.value == nil {
        return false
    }

    // If the objects are the same, then we are good to go
    return lhs.value! === rhs.value!
}

Cela vous permet de faire des trucs cool comme utiliser un Dictionnaire de références faibles:

private var m_observerDict : Dictionary<WeakObject<AnyObject>,FLObservationBlock> = Dictionary()

func addObserver( observer:AnyObject, block:FLObservationBlock )
{
    let weakObserver = WeakObject(value:observer)
    m_observerDict[weakObserver] = block
}


func removeObserver( observer:AnyObject )
{
    let weakObserver = WeakObject(value:observer)
    m_observerDict.removeValueForKey(weakObserver)
}
3
répondu Tod Cunningham 2015-10-05 00:27:54

Voici comment rendre la grande réponse de @ GoZoner conforme à Hashable, de sorte qu'elle peut être indexée dans des objets conteneur comme: Set, Dictionary, Array, etc.

private class Weak<T: AnyObject>: Hashable {
    weak var value : T!
    init (value: T) {
       self.value = value
    }

    var hashValue : Int {
       // ObjectIdentifier creates a unique hashvalue for objects.
       return ObjectIdentifier(self.value).hashValue
    }
}

// Need to override so we can conform to Equitable.
private func == <T>(lhs: Weak<T>, rhs: Weak<T>) -> Bool {
    return lhs.hashValue == rhs.hashValue
}
2
répondu Sakiboy 2015-11-22 23:24:31

Basé sur KAZ Yoshikawa réponse

Détails

XCode 9.1, Swift 4

Solution

WeakObject

import Foundation

protocol WeakObjectProtocol {
    associatedtype WeakObjectType
    var value: WeakObjectType? {get set}
    init(object: WeakObjectType)
}

class WeakObject<T: AnyObject>: WeakObjectProtocol {
    typealias WeakObjectType = T
    weak var value: WeakObjectType?

    required init(object: WeakObjectType) {
        self.value = object
    }

    var referenceCount: Int {
        return CFGetRetainCount(value)
    }
}

extension WeakObject: Equatable {
    static func == (lhs: WeakObject<T>, rhs: WeakObject<T>) -> Bool {
        return lhs.value === rhs.value
    }
}

extension WeakObject: Hashable {
    var hashValue: Int {
        if var value = value { return UnsafeMutablePointer<T>(&value).hashValue }
        return 0
    }
}

extension WeakObject: CustomStringConvertible {

    var description: String {
        if let value = value  {
            let className = String(describing: type(of: value.self))
            return "{class: \(className); referenceCount: \(referenceCount)}"
        }
        return "nil"
    }
}

Tableau D'Extension

import Foundation

extension Array where Element: AnyObject  {

    var weak: Array<WeakObject<Element>> {
        var weakArray = [WeakObject<Element>]()
        for item in self {
            let obj = WeakObject(object: item)
            weakArray.append(obj)
        }
        return weakArray
    }
}

extension Array where Element: WeakObjectProtocol {

    typealias EnumeratedWeakObjectClosure = (_ index: Int, _ value: Element.WeakObjectType?)->()
    typealias WeakObjectClosure = (_ value: Element.WeakObjectType?)->()

    mutating func removeNils() {
        self = self.flatMap{ (element) -> Element? in
            if element.value == nil {
                return nil
            }
            return element
        }
    }

    mutating func append(weakValue: Element.WeakObjectType) {
        append(Element(object: weakValue))
    }

    subscript(index: Int) -> Element.WeakObjectType? {
        get {
            return self[index].value
        }
    }

    func `for` (closure: WeakObjectClosure){
        for item in self {
            closure(item.value)
        }
    }

    func forEnumerated (closure: EnumeratedWeakObjectClosure) {
        for (index,item) in self.enumerated() {
            closure(index, item.value)
        }
    }

    mutating func remove(index: Int, closure: EnumeratedWeakObjectClosure) {
        closure(index, self[index].value)
        remove(at: index)
    }

    mutating func remove(index: Int, closure: WeakObjectClosure) {
        closure(self[index].value)
        remove(at: index)
    }
}

Utilisation

// Array of week objects
var weakArray = [WeakObject<UIView>]()

// Get array of week objects (transfom from [AnyObject])
// way 1
weakArray = view.subviews.weak
// way 2
weakArray = [view.subviews[0], view.subviews[1]].weak

// Add single element to the end of the array
weakArray.append(weakValue: UIView())

// For loop
weakArray.for { (element) in
    print("\(String(describing: element))")
}

// For loop with index (position number)
weakArray.forEnumerated { (index, element) in
    print("\(index) \(String(describing: element))")
}

Échantillon Complet

N'oubliez pas de ajouter le code de la solution ici


ViewController

import UIKit

class ViewController: UIViewController {

    var weakArray = [WeakObject<UIView>]()
    override func viewDidLoad() {
        super.viewDidLoad()
        addSubviews()

        weakArray = view.subviews.weak
        weakArray.append(weakValue: generateView())
        weakArray.remove(index: 0) { item in
            item?.removeFromSuperview()
        }
        weakArray.for { (element) in
            print("\(String(describing: element))")
        }

    }

    func printArray(title: String) {

        print("=============================\n\(title)\ncount: \(weakArray.count)")
        weakArray.forEnumerated { (index,element) in
            print("\(index) \(String(describing: element))")
        }
    }
}

// Creating views

extension ViewController {

    func generateView() -> UIView {
        let randomValue: ()->(CGFloat) = { return CGFloat(rand[50, 300]) }
        let view = UIView(frame: CGRect(x: randomValue(), y: randomValue(), width: randomValue(), height: randomValue()))
        view.backgroundColor = .blue
        let randomColorComponent: ()->(CGFloat) = { return CGFloat(rand[0, 255])/CGFloat(255) }
        let color = UIColor(red: randomColorComponent(), green: randomColorComponent(), blue: randomColorComponent(), alpha: 1)
        view.backgroundColor = color
        self.view.addSubview(view)
        return view
    }

    func addSubviews() {

        _ = generateView()
        _ = generateView()

        addButtons()
    }
}

// Buttons

extension ViewController {

    func addButtons() {
        var button = UIButton(frame: CGRect(x: 10, y: 20, width: 40, height: 40))
        button.setTitle("Add", for: .normal)
        button.addTarget(self, action: #selector(addView), for: .touchUpInside)
        button.setTitleColor(.blue, for: .normal)
        view.addSubview(button)

        button = UIButton(frame: CGRect(x: 60, y: 20, width: 60, height: 40))
        button.setTitle("Delete", for: .normal)
        button.addTarget(self, action: #selector(deleteView), for: .touchUpInside)
        button.setTitleColor(.blue, for: .normal)
        view.addSubview(button)

        button = UIButton(frame: CGRect(x: 120, y: 20, width: 100, height: 40))
        button.setTitle("Remove nil", for: .normal)
        button.addTarget(self, action: #selector(removeNils), for: .touchUpInside)
        button.setTitleColor(.blue, for: .normal)
        view.addSubview(button)
    }

    @objc func deleteView() {
        view.subviews.filter { view -> Bool in
            return !(view is UIButton)
            }.first?.removeFromSuperview()

        DispatchQueue.main.async {
            self.view.layoutIfNeeded()
            self.printArray(title: "First view deleted")
        }
    }

    @objc func addView() {
        weakArray.append(weakValue: generateView())
        printArray(title: "View addded")
    }

    @objc func removeNils() {
        weakArray.removeNils()
        printArray(title: "Remove all nil elements in weakArray")
    }
}

Rand func

class Random {

    subscript<T>(_ min: T, _ max: T) -> T where T : BinaryInteger {
        get {
            return rand(min-1, max+1)
        }
    }
}

let rand = Random()

func rand<T>(_ min: T, _ max: T) -> T where T : BinaryInteger {
    let _min = min + 1
    let difference = max - _min
    return T(arc4random_uniform(UInt32(difference))) + _min
}

Résultat

entrez la description de l'image ici

2
répondu Vasily Bodnarchuk 2017-11-23 21:02:08

D'autres réponses ont couvert l'angle des génériques. Je pensais partager un code simple couvrant l'angle nil.

Je voulais un tableau statique (lu occasionnellement) de tous les Label qui existent actuellement dans l'application, mais je ne voulais pas voir nil où se trouvaient les anciens.

Rien d'extraordinaire, c'est mon code...

public struct WeakLabel {
    public weak var label : Label?
    public init(_ label: Label?) {
        self.label = label
    }
}

public class Label : UILabel {
    static var _allLabels = [WeakLabel]()
    public static var allLabels:[WeakLabel] {
        get {
            _allLabels = _allLabels.filter{$0.label != nil}
            return _allLabels.filter{$0.label != nil}.map{$0.label!}
        }
    }
    public required init?(coder: NSCoder) {
        super.init(coder: coder)
        Label._allLabels.append(WeakLabel(self))
    }
    public override init(frame: CGRect) {
        super.init(frame: frame)
        Label._allLabels.append(WeakLabel(self))
    }
}
1
répondu wils 2015-09-27 07:09:45

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 permettant de stocker une structure aussi.

[Je ne suis pas sûr de son utilité, mais il a fallu un certain temps pour obtenir la bonne syntaxe]

class WeakWrapper : Equatable {
    var valueAny : Any?
    weak var value : AnyObject?

    init(value: Any) {
        if let valueObj = value as? AnyObject {
            self.value = valueObj
        } else {
            self.valueAny = value
        }
    }

    func recall() -> Any? {
        if let value = value {
            return value
        } else if let value = valueAny {
            return value
        }
        return nil
    }
}


func ==(lhs: WeakWrapper, rhs: WeakWrapper) -> Bool {
    return ObjectIdentifier(lhs) == ObjectIdentifier(rhs)
}



class Stuff {}
var weakArray : [WeakWrapper] = [WeakWrapper(value: Stuff()), WeakWrapper(value: CGRectZero)]

extension Array where Element : WeakWrapper  {

    mutating func removeObject(object: Element) {
        if let index = self.indexOf(object) {
            self.removeAtIndex(index)
        }
    }

    mutating func compress() {
        for obj in self {
            if obj.recall() == nil {
                self.removeObject(obj)
            }
        }
    }


}

weakArray[0].recall()
weakArray[1].recall() == nil
weakArray.compress()
weakArray.count
1
répondu Dan Rosenstark 2015-11-24 05:42:23

Vous pouvez créer un wrapper autour de Array. Ou utilisez cette bibliothèque https://github.com/NickRybalko/WeakPointerArray let array = WeakPointerArray<AnyObject>() Il est de type sûr.

1
répondu Nick Rybalko 2017-07-19 14:03:33

J'ai basé cela sur le travail de @Eonil, puisque j'aimais la stratégie de fermeture à 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:

class Weak<T> where T: AnyObject {
    fileprivate var storedWeakReference: ()->T? = { return nil }

    var value: T? {
        get {
            return storedWeakReference()
        }
    }

    init(_ object: T) {
        self.storedWeakReference = storeWeakReference(object)
    }

    fileprivate func storeWeakReference<T> (_ target:T) -> ()->T? where T: AnyObject {
        return { [weak target] in
            return target
        }
    }
}

De Cette façon, vous pouvez faire quelque chose comme:

var a: UIViewController? = UIViewController()
let b = Weak(a)
print(a) //prints Optional(<UIViewController: 0xSomeAddress>)
print(b.value) //prints Optional(<UIViewController: 0xSomeAddress>)
a = nil
print(a) //prints nil
print(b.value) //prints nil
0
répondu Ale Ravasio 2018-08-16 21:36:39

Puisque NSPointerArray gère déjà la plupart de cela automatiquement, j'ai résolu le problème en faisant un wrapper de type-safe pour cela, ce qui évite beaucoup de passe-partout dans d'autres réponses:

class WeakArray<T: AnyObject> {
    private let pointers = NSPointerArray.weakObjects()

    init (_ elements: T...) {
        elements.forEach{self.pointers.addPointer(Unmanaged.passUnretained($0).toOpaque())}
    }

    func get (_ index: Int) -> T? {
        if index < self.pointers.count, let pointer = self.pointers.pointer(at: 0) {
            return Unmanaged<T>.fromOpaque(pointer).takeUnretainedValue()
        } else {
            return nil
        }
    }
    func append (_ element: T) {
        self.pointers.addPointer(Unmanaged.passUnretained(element).toOpaque())
    }
    func forEach (_ callback: (T) -> ()) {
        for i in 0..<self.pointers.count {
            if let element = self.get(i) {
                callback(element)
            }
        }
    }
    // implement other functionality as needed
}

Exemple d'utilisation:

class Foo {}
var foo: Foo? = Foo()
let array = WeakArray(foo!)
print(array.get(0)) // Optional(Foo)
foo = nil
DispatchQueue.main.async{print(array.get(0))} // nil

C'est plus de travail à l'avant, mais l'utilisation dans le reste de votre code est beaucoup plus propre IMO. Si vous voulez le rendre plus semblable à un tableau, vous pouvez même implémenter l'subscripting, en faire un SequenceType, etc. (mais mon projet n'a besoin que de append et forEach donc je n'ai pas le code exact sur main).

0
répondu John Montgomery 2018-09-14 18:13:50