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


当前回答

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

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

NSHashTable类引用

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

其他回答

可以围绕Array创建包装器。或者使用这个库https://github.com/NickRybalko/WeakPointerArray let array =弱指针数组<AnyObject>() 它是类型安全的。

创建一个通用包装器,如下:

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

将该类的实例添加到数组中。

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

定义Weak时,可以使用struct或class。

同样,为了帮助获取数组内容,你可以做一些如下的事情:

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

上面使用的AnyObject应该替换为T -但我不认为当前的Swift语言允许这样定义扩展。

下面是如何使@GoZoner的伟大的答案符合哈希,所以它可以在容器对象中索引:集,字典,数组等。

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
}

现有的WeakContainer示例很有帮助,但它并不能真正帮助在现有的快速容器(如列表和字典)中使用弱引用。

如果您想使用List方法,如contains,那么WeakContainer将需要实现Equatable。因此,我添加了允许WeakContainer是相等的代码。

如果您想在字典中使用WeakContainer,我还将其设置为可哈希的,以便可以将其用作字典键。

我还将其重命名为WeakObject,以强调这仅适用于类类型,并将其与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!
}

这允许你做一些很酷的事情,比如使用弱引用字典:

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

我基于@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