如何在Swift中声明一个弱引用数组?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在Swift中声明一个弱引用数组?相关的知识,希望对你有一定的参考价值。

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

答案

创建一个通用包装器:

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时,您可以使用structclass

此外,为了帮助获取数组内容,您可以执行以下操作:

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

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

另一答案

以下是如何使@ GoZoner的答案符合Hashable,因此它可以在Container对象中编入索引,例如:SetDictionaryArray等。

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
}
另一答案

其他答案涵盖了泛型角度。以为我会分享一些涵盖nil角度的简单代码。

我想要一个当前存在于应用程序中的所有Labels的静态数组(偶尔读取),但是不想看到旧的那些曾经是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))
    }
}
另一答案

针对同一问题的又一个解决方案......这个问题的重点是存储对象的弱引用,但也允许存储结构。

[我不确定它有多有用,但确实需要一段时间才能使语法正确]

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
另一答案

由于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: 0) {
            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

它预先做的更多,但在其余代码中的使用更加清晰IMO。如果你想让它更像数组,你甚至可以实现下标,使它成为SequenceType等(但我的项目只需要appendforEach所以我手头没有确切的代码)。

另一答案

你可以在Array周围创建包装器。或使用此库https://github.com/NickRybalko/WeakPointerArray let array = WeakPointerArray<AnyObject>() 它是类型安全的。

另一答案

我基于@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
另一答案

我的解决方案:

  • 解除分配时清理数组,因为WeakObjectSet正在存储而不是从WeakObject中删除
  • 在Set中找到重复元素时解决致命错误

--

// MARK: - WeakObjectSet 

public class WeakObject<T: AnyObject>: Equatable, Hashable {

    // MARK: Public propreties

    public weak var object: T?
    public var hashValue: Int {
        return self.identifier.hashValue
    }

    // MARK: Private propreties

    private let identifier: ObjectIdentifier

    // MARK: Initializer

    public init(object: T) {
        self.identifier = ObjectIdentifier(object)
        self.object = object
    }

    public static func == (lhs: WeakObject<T>, rhs: WeakObject<T>) -> Bool {
        return lhs.identifier == rhs.identifier
    }
}

// MARK: - WeakObjectSet

public class WeakObjectSet<T: AnyObject> {

    // MARK: Public propreties

    public var allObjects: [T] {
        return allSetObjects.compactMap { $0.object }
    }

    // MARK: Private propreties

    private var objects: Set<WeakObject<T>>
    private var allSetObjects: Set<WeakObject<T>> {
        get {
            objects = self.objects.filter { $0.object != nil }
            return objects
        }
        set {
            objects.formUnion(newValue.filter { $0.object != nil })
        }
    }

    // MARK: Initializer

    public init() {
        self.objects = Set<WeakObject<T>>([])
    }

    public init(objects: [T]) {
        self.objects = Set<WeakObject<T>>(objects.map { WeakObject(object: $0) })
    }

    // MARK: Public function

    public func contains(_ object: T) -> Bool {
        return self.allSetObjects.contains(WeakObject(object: object))
    }

    public func addObject(_ object: T) {
        self.allSetObjects.insert(WeakObjec

以上是关于如何在Swift中声明一个弱引用数组?的主要内容,如果未能解决你的问题,请参考以下文章

Swift如何实现通用类型的弱引用数组(下)

Swift如何实现通用类型的弱引用数组(下)

翻译: Swift 中的委托保留周期 如何在“纯”Swift(没有@objc)中进行弱协议引用

如何在作为协议类型的 Swift 通用数据结构中使用弱引用?

Android 我应该在异步任务中将片段作为弱引用传递吗?

如何将弱引用对象存储在数组中,字典中的objc?