我想在Swift中存储一个弱引用数组。数组本身不应该是弱引用——它的元素应该是。我认为Cocoa NSPointerArray提供了一个非类型安全的版本。


当前回答

在很多情况下,返回一个可取消的选项会更简洁。这允许调用站点决定何时显式地销毁值(以及通过解压缩隐式地销毁值):


public protocol Cancellable {
    func cancel()
}

private struct MyValue: Identifiable {
    let id: String
    // ...
}

private class CancellationHandler: Cancellable {
    let handler: () -> ()
    init(handler: @escaping () -> ()) { self.handler = handler }
    func cancel() { handler() }
    deinit { handler() }
}

public class Container {
    private var array = [MyType]()

    public func add() -> Cancellable {
        let value = MyValue(...)
        array.append(value)
        return CancellationHandler {
            array.removeFirst(where: { $0.id == value.id })
        }
    }
}

let cancellable = container.add()

// Both cancellable.cancel() and the cancellable descoping 
// will call the `cancel` function, removing the value from array.

其他回答

函数式编程方法

不需要额外的课程。

简单地定义一个闭包数组()-> Foo?并使用[weak foo]将foo实例捕获为弱实例。

let foo = Foo()

var foos = [() -> Foo?]()
foos.append({ [weak foo] in return foo })

foos.forEach { $0()?.doSomething() }

我有同样的想法来创建带有泛型的弱容器。 因此,我为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?
        }
    }
}

用法:

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()
}

这不是最好的解决方案,因为WeakSet可以初始化为任何类型,如果这种类型不符合AnyObject协议,那么应用程序将崩溃,并给出详细的原因。但我现在找不到更好的解决办法。

最初的解决方案是这样定义WeakSet:

class WeakSet<ObjectType: AnyObject>: SequenceType {}

但是在这种情况下,WeakSet不能用协议初始化:

protocol MyDelegate : AnyObject {
    func doWork()
}

let weakSet = WeakSet<MyDelegate>()

目前以上代码无法编译(Swift 2.1, Xcode 7.1)。 这就是为什么我放弃符合AnyObject并使用fatalError()断言添加额外的保护。

其他的回答涵盖了泛型的角度。我想分享一些涵盖nil角度的简单代码。

我想要一个静态数组(偶尔读)的所有标签,目前存在于应用程序,但不想看到nil的地方旧的曾经是。

没什么特别的,这是我的代码…

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))
    }
}

你可以和weakObjectsHashTable一起使用NSHashTable。NSHashTable < ObjectType > .weakObjectsHashTable ()

对于Swift 3: NSHashTable<ObjectType>.weakObjects()

NSHashTable类引用

OS X v10.5及以上版本支持。 支持iOS 6.0及以上版本。

我基于@Eonil的工作,因为我喜欢闭包弱绑定策略,但我不想为变量使用函数操作符,因为这感觉非常违反直觉

相反,我所做的是:

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
        }
    }
}

这样你可以做一些事情,比如:

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