【问题标题】:Swift and RAII: deinit behavior inconsistent between project and playgroundSwift 和 RAII:项目和游乐场之间的 deinit 行为不一致
【发布时间】:2019-12-15 13:04:47
【问题描述】:

让我先声明我已经阅读了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 实例的 deinit 发生在 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. 有没有办法控制/保证项目中使用的行为?如果可能的话,我想要游乐场的行为。

【问题讨论】:

    标签: swift xcode swift-playground


    【解决方案1】:

    Playground 对对象进行各种引用,以便在侧边栏和结果预览中显示它们。

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

    【讨论】:

      【解决方案2】:

      Playground 的编译方式不同 - 与常规编译不同,编译器将您的代码转换为 inserting various calls to instrumentation。例如,这使您可以查看表达式的计算结果。但是,它可能会带来不幸的副作用,即改变程序的行为方式。

      值得注意的是,与 C 和 C++ 等语言不同,Swift 不保证局部变量(或者在您的情况下,未使用的表达式中的值)在定义它们的范围结束之前保持有效。优化器可以提前取消初始化它们。

      如果你想在你的例子中保证SomeClass的生命周期,你可以使用withExtendedLifetime

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-19
        相关资源
        最近更新 更多