Swift 在作用域结束之前,编译器是否隐式取消包装可选变量?

Swift 在作用域结束之前,编译器是否隐式取消包装可选变量?,swift,variables,scope,rx-swift,Swift,Variables,Scope,Rx Swift,通过swift编译器优化,隐式展开的可选变量不会在整个范围内存在,而是在使用后立即释放 这是我的环境: swift --version 输出 Apple Swift version 5.3.2 (swiftlang-1200.0.45 clang-1200.0.32.28) Target: x86_64-apple-darwin20.2.0 Xcode版本是版本12.3(12C33) 考虑这个最基本的例子来说明问题: final类SomeClass{ func doSth(){} 脱硝{ 印

通过swift编译器优化,隐式展开的可选变量不会在整个范围内存在,而是在使用后立即释放

这是我的环境:

swift --version
输出

Apple Swift version 5.3.2 (swiftlang-1200.0.45 clang-1200.0.32.28)
Target: x86_64-apple-darwin20.2.0
Xcode版本是
版本12.3(12C33)

考虑这个最基本的例子来说明问题:

final类SomeClass{
func doSth(){}
脱硝{
印刷品(“脱硝”)
}
}
func do(){
var someObject:SomeClass!=SomeClass()
someObject.doSth()
打印(“完成”)
}
这应该是个好消息

done
deinit
但是,在发布版本中(启用了Swift代码优化“-O”),它以另一种方式打印:

deinit
done
这仅适用于
var someObject:SomeClass

该代码的以下更改正确地完成了所有输出(意味着当函数的作用域离开时对象被释放):

将var定义为常量:

func-dosthsspecial(){
让someObject:SomeClass!=SomeClass()
someObject.doSth()
打印(“完成”)
}
明确将var定义为可选:

func-dosthsspecial(){
var someObject:SomeClass?=SomeClass()
someObject.doSth()
打印(“完成”)
}
访问权限(如可选):

func-dosthsspecial(){
var someObject:SomeClass!=SomeClass()
someObject?.doSth()
打印(“完成”)
}
最后三个实现都是输出

done
deinit
按这个顺序

不知怎的,这让我哑口无言 但是作为一个程序员,我们习惯于在函数中使用局部变量,直到离开作用域为止

自从ARC首次为ObjC发布以来,情况就不是这样了。ARC始终可以选择在上次使用对象后释放对象(并且经常使用此选项)。这是经过设计的,在Swift(或者在ObjC中也是如此)中不是一个bug

在Swift中,如果要将对象的生存期延长到其最后一次使用之后,则显式地用于此目的

var someObject: SomeClass! = SomeClass()

withExtendedLifetime(someObject) {
    someObject.doSth()
    print("done")
}
请记住,对象对其进行平衡的retain/AUTORELASE调用是合法的,这可能会导致它们超出其范围。这在Swift中不太常见,但仍然是合法的,如果您将Swift对象传递给ObjC,就会发生这种情况(这可能发生在许多您可能无法预料的地方)

您应该非常小心地依赖于何时调用
deinit
。它可以让你吃惊,甚至在所有情况下都没有承诺(例如,在C++上的程序退出时不调用代码> DENITIT <代码>,这会使C++开发者感到惊讶)。 IMO
performAsyncSyncTask
是一种危险的模式,应该以更清晰的所有权重新设计。我没有做足够的RxSwift工作来立即重新设计它,但是在DispatchSemaphore上阻塞整个线程似乎是与任何反应式系统集成的错误方式。线程是一种有限的资源,这迫使系统创建更多的线程,而这个线程被阻塞,不做任何事情