类型擦除:当擦除类型信息时,我们是否会冒不可挽回地失去对擦除类型实例的保持活动数据的访问的风险?

时间:2016-09-14 20:10:15

标签: swift type-erasure

考虑以下常见的简单类型擦除方案

protocol Foo {
    associatedtype Bar
    func bar() -> Bar
}

struct AnyFoo<Bar>: Foo {
    private let _bar: () -> Bar

    init<F: Foo>(_ foo: F) where F.Bar == Bar {
        _bar = foo.bar
            /* stores a reference to foo.bar,
               so foo kept alive by ARC? */
    }

    func bar() -> Bar {
        return _bar()
    }
}

假设上面的初始化参数foo是(意图是)&#34; large&#34;的临时实例。类型,我们从中只对切出Foo蓝图的信息(即bar()方法)感兴趣。

struct Huge { /* ... */ }

struct Foobar: Foo {
    internal func bar() -> String {
        return "foo"
    }
    let lotsOfData: Huge = Huge()
}

func getAnyFooStr() -> AnyFoo<String> {
    let foobar = Foobar()
    return AnyFoo(foobar)
}

let anyStrFoo = getAnyFooStr()
    /* we can now access anyStrFoo.bar() (-> "foo") from our
       erased type, but do lotsOfData of the underlying seemingly
       temporary Foobar() instance still "live", unreachable? */
  • 问:由于闭包是引用类型,我们是否仍会将foo的剩余内容保留在内存中且无法访问?如果是这样,我认为我们永远无法回收这种丢失但活着的内容?

(我尝试使用Foobar作为课程进行上述操作,监控(缺少一个)deinit电话,但是我在最后一个小时内对自己感到很困惑需要一些非自我验证,特别是对于Foobar是值类型的情况)

Xcode 8.0 / Swift 3。

1 个答案:

答案 0 :(得分:2)

是的,它与类型擦除无关:) 闭包Foobar().bar保留它绑定的实例 (只要封闭处于活着状态),它的所有属性都会存活。

这是一个简化的例子:

class Huge {
    deinit { print("deinit Huge") }
}

struct Foobar {
    internal func bar() -> String {
        return "foo"
    }
    let lotsOfData: Huge = Huge()
}

do {
    let fb  = Foobar().bar // the type of `fb` is `() -> String`
    print("still alive ...")
}
print("... out of scope now")

输出:

still alive ...
deinit Huge
... out of scope now