但是,当局部变量引用这些实例时,Swift语言和运行时对实例生命周期的确切保证是什么?例如.当局部变量持有对它的唯一引用时,实例可能被释放的最早点是什么?
在下面的示例中,我创建了一个类的实例,并在局部变量中存储对它的引用.
public final class Something { init() { print("something.init()") } deinit { print("something.deinit()") } } func useSomething() { let something = Something() print("useSomething()") } useSomething()
在我打印useSomething()之后不使用该变量,但是在调用print()之后deinit运行一致:
$swift run -c release something.init() useSomething() something.deinit()
似乎引用总是在变量超出范围时递减.在do块中包装变量声明会更改顺序:
func useSomething() { do { let something = Something() } print("useSomething()") }
$swift run -c release something.init() something.deinit() useSomething()
这个订单是保证还是可以用不同的编译器或优化级别更改?
我对此感兴趣的原因是我想在面向对象的Swift API中包装C API,并希望使用Swift类和引用计数自动管理使用C API分配的资源的生命周期.如果C API的每次使用都需要对其操作的资源的引用,那么这很有用,因为我知道Swift实例将至少存活到对实例所代表的资源进行操作的最后一次调用.
但是一些API使用全局状态来选择资源,并且对API的后续调用不需要引用要传递的资源,而是隐式地对所选资源进行操作. OpenGL的glDrawElements()隐式使用5或10个这样的资源(顶点数组,着色器,帧缓冲区,纹理……).
Swift不保证对象的生命周期直到最近的范围的末尾,例如,参见
Swift论坛中的以下主题:
> Should Swift apply “statement scope” for ARC
> ARC // Precise Lifetime Semantics
如果声明你可以使用withExtendedLifetime(_:_:)
:
Evaluates a closure while ensuring that the given instance is not destroyed before the closure returns.
为了这个目的.至于理由,
Dave Abrahams (Apple)州:
The lack of such a guarantee, which is very seldom actually useful
anyhow, is what allows us to turn costly copies (with associated
refcount traffic and, often CoW allocation and copying fallout) into
moves, which are practically free. Adopting it would basically kill our
performance story for CoW.
和Joe Groff (Apple)在同一个帖子中:
Yeah, if you want to vend resources managed by an object to consumers outside of that object like this, you need to use withExtendedLifetime to keep the object alive for as long as you’re using the resources. A cleaner way to model this might be to put the class or protocol in control of handling the I/O to the file handle, instead of vending the file handle itself, so that the ownership semantics fall out more naturally: