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


当前回答

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

其他回答

同样的问题还有另一种解决方案……它的重点是存储对对象的弱引用,但也允许存储结构。

[我不确定它有多有用,但它确实花了一段时间来纠正语法]

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

函数式样式包装器呢?

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)

只需调用返回的闭包来检查目标是否仍然存在。

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

你可以把闭包存储到一个数组中。

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

您可以通过映射调用闭包来检索弱捕获的值。

let values = Array(array1.map({ $0() }))

实际上,你不需要一个函数来创建闭包。直接捕获一个对象。

let captured3 = { [weak obj3] in return obj3 }

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

@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的伟大的答案符合哈希,所以它可以在容器对象中索引:集,字典,数组等。

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
}

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