Swift和RAII:项目和游乐场之间的初始行为不一致

时间:2019-08-07 20:46:52

标签: swift xcode swift-playground

让我通过this other questiondocumentation for ARC中的所有内容来开始我的提问。

我正在尝试使用RAII惯用语来处理问题,并且遇到了一些导致其无法正常工作的不一致之处。

这是一个说明不一致的示例:

class TestClass {
    init() {
        print("init")
    }
    deinit {
        print("deinit")
    }
}

func test() {
    TestClass()
    defer { print("defer") }
    print("end of scope")
}

test()

根据我的c ++经验,我期望TestClass实例的取消初始化发生在test函数范围的末尾,这是我想要做的事情。

与此同时,我意识到我正在初始化TestClass的实例,但没有将其存储在变量中,因此并没有对其的严格引用,因此将其正确地释放是有意义的离开。

因此出现问题是因为项目和游乐场之间的行为不一致。

在操场上,上面的代码产生以下输出:

init
end of scope
defer
deinit // deinit happens at end of scope
after scope

但是在项目中,完全相同的代码会产生不同的结果:

init
deinit // deinit happens immediately
end of scope
defer
after scope

所以

  1. 为什么项目和游乐场之间的行为有所不同?
  2. 是否有一种方法可以控制/保证在项目中使用哪种行为?如果可能的话,我想在操场上表现。

2 个答案:

答案 0 :(得分:2)

游乐场对对象进行各种引用,以将其显示在边栏中并预览结果。

您应该认为游乐场的强引用是完全不确定的。对于任何真正的生命周期调试,您都需要在独立程序,库等中运行代码。

答案 1 :(得分:2)

操场不是“真正的Swift”-与常规编译不同,编译器通过插入各种对工具的调用来转换代码。例如,这使您可以查看表达式的计算结果。但是,不幸的是,它可能会改变程序的行为。

但是,值得注意的是,与C和C ++之类的语言不同,Swift不能保证局部变量(或者您的情况是未使用的表达式中的值)在定义它们的作用域结束之前保持有效。优化器可以自由地对其进行早期初始化。

如果要保证示例中SomeClass的生命周期,可以使用withExtendedLifetime

func test() {
  withExtendedLifetime(TestClass()) {
    defer { print("defer") }
    print("end of scope")
  }
}