快速数组保持元素弱

时间:2018-09-08 15:49:48

标签: arrays swift generics memory weak-references

我从

中汲取了一些灵感

https://marcosantadev.com/swift-arrays-holding-elements-weak-references/

并且我希望能够维护一个数组,该数组持有对其元素的弱引用,以防万一这些元素在我的代码库中的其他位置释放,我不会将它们保留在我的数组中。

我希望实现尽可能安全,但是应该可以重用。

我使用的策略是这样声明弱引用容器。

class WeakRefContainer<T> where T: AnyObject {
    private(set) weak var value: T?

    init(value: T?) {
        self.value = value
    }
}

然后我要维护这些WeakRefContainers的数组,因此我创建了一个数组扩展名:

extension Array where Element: WeakRefContainer<AnyObject> {
    func compact() -> [WeakRefContainer<AnyObject>] {
        return filter { $0.value != nil }
    }
}

调用紧凑方法时,我现在可以清理数组,以防需要清理东西。

我现在遇到一些编译问题,难以理解。 假设我有一个示例类

class SampleClass {
}

我尝试使用以下所有内容:

var weakReferencesArray = [WeakRefContainer<SampleClass>]()
let obj1 = WeakRefContainer.init(value: SampleClass())
let obj2 = WeakRefContainer.init(value: SampleClass())
weakReferencesArray.append(obj1)
weakReferencesArray.append(obj2)

weakReferencesArray.compact()

当我尝试调用紧凑型计算机时,出现以下错误消息:

MyPlayground.playground:29:21: 'WeakRefContainer<SampleClass>' is not a subtype of 'WeakRefContainer<AnyObject>'

有人可以解除对我的封锁吗?谢谢

2 个答案:

答案 0 :(得分:1)

您的代码不起作用,因为WeakRefContainer<SampleClass>不是WeakRefContainer<AnyObject>的子类,因为在Swift中泛型是不变的。因此weakReferencesArray不能使用从扩展名中添加的compact方法。

通过协议可以解决此问题:

protocol WeakHolder {
    var hasRef: Bool { get }
}

extension WeakRefContainer: WeakHolder {
    var hasRef: Bool { return value != nil }
}

extension Array where Element: WeakHolder {

    func compacted() -> [Element] {
        return filter { $0.hasRef }
    }

    mutating func compact() {
        self = compacted()
    }
}

为了更好的Swift语义,我还将compact重命名为compacted,并用一个可变版本代替了原来的compact

答案 1 :(得分:1)

您可能希望扩展名适用于所有[WeakRefContainer<T>],其中T可以是扩展AnyObject的任何类型。

extension Array where Element: WeakRefContainer<T> {

但是,当前无法进行参数化扩展。参见this proposal

您可以通过使compact通用来解决此问题:

extension Array{
    func compact<T>() -> [Element] where Element == WeakRefContainer<T> {
        return filter { $0.value != nil }
    }
}