Feu*_*mel 3 class automatic-ref-counting swift
在Swift中,我可以使用ARC机制来管理进程外部资源的生命周期,因为类的实例可以预先解除初始化.这与Java Runtime之类的环境形成对比,在Java Runtime中,当垃圾收集器收集对象时,实例被去初始化,这不能保证在定义的时间窗口中发生.
但是,当局部变量引用这些实例时,Swift语言和运行时对实例生命周期的确切保证是什么?例如,当局部变量持有对它的唯一引用时,实例可能被解除分配的最早点是什么?
在下面的示例中,我创建了一个类的实例,并在局部变量中存储对它的引用.
public final class Something {
init() { print("something.init()") }
deinit { print("something.deinit()") }
}
func useSomething() {
let something = Something()
print("useSomething()")
}
useSomething()
Run Code Online (Sandbox Code Playgroud)
在我打印的点之后不使用该变量,useSomething()但在调用之后deinit运行一致:print()
$ swift run -c release
something.init()
useSomething()
something.deinit()
Run Code Online (Sandbox Code Playgroud)
似乎引用总是在变量超出范围时递减.在do块中包装变量声明会更改顺序:
func useSomething() {
do { let something = Something() }
print("useSomething()")
}
Run Code Online (Sandbox Code Playgroud)
$ swift run -c release
something.init()
something.deinit()
useSomething()
Run Code Online (Sandbox Code Playgroud)
这个订单是保证还是可以用不同的编译器或优化级别更改?
我对此感兴趣的原因是我想在面向对象的Swift API中包装C API,并希望使用Swift类和引用计数自动管理使用C API分配的资源的生命周期.如果C API的每次使用都需要对其操作的资源的引用,那么这很有用,因为我知道Swift实例将至少存活到对实例所代表的资源进行操作的最后一次调用.
但是一些API使用全局状态来选择资源,并且对API的后续调用不需要引用要传递的资源,而是隐式地对所选资源进行操作.OpenGL glDrawElements()隐含地使用5或10个这样的资源(顶点数组,着色器,帧缓冲区,纹理......).
Swift不保证对象的生命周期直到最近的范围结束,例如参见Swift论坛中的以下线程:
如果声明你可以使用withExtendedLifetime(_:_:):
计算闭包,同时确保在闭包返回之前不会销毁给定的实例.
为了这个目的.至于理由, Dave Abrahams(Apple)说:
缺乏这种保证,无论如何实际上很少有用,是允许我们将昂贵的副本(具有相关的refcount流量,通常是CoW分配和复制余量)转换为实际上免费的移动.采用它基本上会扼杀我们对CoW的表现.
和Joe Groff(Apple)在同一个帖子中:
是的,如果你想将一个对象管理的资源出售给那个对象之外的消费者,你需要使用withExtendedLifetime来保持对象的活着,只要你使用这些资源.一种更简洁的方法可能是将类或协议置于控制处理文件句柄的I/O,而不是出售文件句柄本身,这样所有权语义就会更自然地消失: