【问题标题】:Swift Array holding elements weaklySwift Array 弱保存元素
【发布时间】:2019-02-13 15:41:56
【问题描述】:

我从

中获得了一些灵感

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 }
    }
}

当调用 compact 方法时,我现在可以清理数组以防需要清理内容。

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

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()

当我尝试调用 compact 时,我收到以下错误消息:

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

有人可以解封吗?谢谢

【问题讨论】:

  • 你应该让你的WeakRefContainer 成为一个结构体。
  • 我会避免在Array 上使用方法名称compact(),因为如果compactMap 的身份映射版本被添加到标准库中,它很可能会被命名。

标签: arrays swift generics memory weak-references


【解决方案1】:

您可能希望扩展适用于所有[WeakRefContainer&lt;T&gt;],其中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 }
    }
}

【讨论】:

  • 另一个选项是extension Array { func compact&lt;T&gt;() -&gt; [Element] where Element == WeakRefContainer&lt;T&gt; { :)
  • @Hamish 哦,我不知道你可以像 that 那样限制Element!谢谢!
【解决方案2】:

您的代码不起作用,因为 WeakRefContainer&lt;SampleClass&gt; 不是 WeakRefContainer&lt;AnyObject&gt; 的子类,因为泛型在 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 替换为变异版本。

【讨论】:

    猜你喜欢
    • 2011-09-21
    • 1970-01-01
    • 2015-09-27
    • 1970-01-01
    • 1970-01-01
    • 2014-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多