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


当前回答

这不是我的解决方案。我是在苹果开发者论坛上找到它的。

@GoZoner有一个很好的答案,但它崩溃了Swift编译器。

下面是一个弱对象容器的版本,它不会使当前发布的编译器崩溃。

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

    init (value: T) {
        _value = value
    }

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

然后你可以创建一个这些容器的数组:

let myArray: Array<WeakContainer<MyClass>> = [myObject1, myObject2]

其他回答

这不是我的解决方案。我是在苹果开发者论坛上找到它的。

@GoZoner有一个很好的答案,但它崩溃了Swift编译器。

下面是一个弱对象容器的版本,它不会使当前发布的编译器崩溃。

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

    init (value: T) {
        _value = value
    }

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

然后你可以创建一个这些容器的数组:

let myArray: Array<WeakContainer<MyClass>> = [myObject1, myObject2]

可以通过创建包装器对象来保存弱指针来实现这一点。

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

然后在数组中使用这些

var weakThings = WeakThing<Foo>[]()

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

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

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语言允许这样定义扩展。

现有的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)
}