我想在Swift中存储一个弱引用数组。数组本身不应该是弱引用——它的元素应该是。我认为Cocoa NSPointerArray提供了一个非类型安全的版本。
当前回答
下面是如何使@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
}
其他回答
由于NSPointerArray已经自动处理了大部分问题,我通过为它做一个类型安全的包装来解决这个问题,这避免了其他答案中的大量样板:
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: index) {
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
}
使用示例:
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
它在前面做了更多的工作,但在你的代码的其余部分的使用是更干净的我。如果你想让它更像数组,你甚至可以实现下标,使它成为一个SequenceType等(但我的项目只需要append和forEach,所以我手头没有确切的代码)。
可以通过创建包装器对象来保存弱指针来实现这一点。
struct WeakThing<T: AnyObject> {
weak var value: T?
init (value: T) {
self.value = value
}
}
然后在数组中使用这些
var weakThings = WeakThing<Foo>[]()
现有的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)
}
创建一个通用包装器,如下:
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语言允许这样定义扩展。
函数式编程方法
不需要额外的课程。
简单地定义一个闭包数组()-> Foo?并使用[weak foo]将foo实例捕获为弱实例。
let foo = Foo()
var foos = [() -> Foo?]()
foos.append({ [weak foo] in return foo })
foos.forEach { $0()?.doSomething() }
推荐文章
- 如何删除默认的导航栏空间在SwiftUI导航视图
- 如何在iOS中使用Swift编程segue
- Swift -整数转换为小时/分钟/秒
- 如何舍入一个双到最近的Int在迅速?
- 扁平化数组的数组在Swift
- Swift:声明一个空字典
- 为什么ARC仍然需要@autoreleasepool ?
- 从数组中随机选择一个元素
- Java:强/软/弱/幻影引用的区别
- 在Swift中如何调用GCD主线程上的参数方法?
- swift语言中的结构与类
- 我如何在Swift连接字符串?
- 我应该如何从字符串中删除所有的前导空格?- - - - - -斯威夫特
- 新的自动引用计数机制是如何工作的?
- Swift:理解// MARK