这是我的测试代码(在终端中运行):
#!/usr/bin/xcrun swift
var count = 0; // for reference counting
class A {
init() {
count++;
}
deinit {
println("A deinit")
count--;
}
}
var a: A? = A()
println(count)
a = nil // no output if I comment out this statement
println(count)
输出:
1
A deinit
0
如果上面提到的行被注释掉,则没有输出“A deinit”。输出将是:
1
1
我使用swiftc
编译代码但结果仍然相同。 (xcrun swiftc -o test test.swift
)
是否按设计在程序退出时关闭stdout,或者当它们被破坏时仍然引用对象(通过什么?)?
当它在函数内运行时,即使我注释掉A deinit
,它也会输出a = nil
:
#!/usr/bin/xcrun swift
class A {
deinit {
println("A deinit")
}
}
func test() {
var a: A? = A()
//a = nil
}
test()
我没有在Xcode中使用游乐场。 : - $
#!/usr/bin/xcrun swift
import Foundation
class A {
deinit {
var s = "A deinit"
println(s)
var a: A? = A()
a = nil
var error: NSError?
var path = "\(NSFileManager.defaultManager().currentDirectoryPath)/swift_test.txt"
if s.writeToFile(path, atomically: true, encoding: NSUTF8StringEncoding, error: &error) {
println("File saved at \(path)")
} else {
println(error)
}
}
}
//func test() {
var a: A? = A()
//}
//test()
结果:除非在test
函数中运行,否则不输出到stdout或文件。
答案 0 :(得分:7)
虽然我没有看到一个明确的引用说明" Swift的deinit
与ObjC dealloc
具有完全相同的语义,&#34 ;很难想象这不是真的,因为Swift和ObjC对象都由ARC管理,一般来说可以互换。
鉴于此,这是完全可以预期的。 Cocoa在程序终止时不会释放对象。它只是终止,泄漏所有内存,文件句柄和其他系统资源,并将其留给操作系统进行清理。这使得程序终止速度明显快于其他情况。
这一点非常重要,因为这意味着您通常不应使用deinit
来管理除OS管理资源之外的任何内容(当然不是您要求运行的任何内容)。当然,即使在C ++中,也无法保证析构函数运行。如果你崩溃了,它就不会发生,你的程序将不得不处理这个问题。您可以将其想象为所有Cocoa程序在终止时悄然崩溃。
因此,在您的情况下,a = nil
导致deinit
运行,而程序终止则不会。
答案 1 :(得分:0)
程序正在退出,你想知道在早期的Swift实现中是否存在竞争(例如Swift实现错误)。绝对应该在正常程序退出时调用退出处理程序(而不是SIGKILL)。
我建议在deinit中创建一个文件,并在程序退出后检查它是否存在,但是如果推测I / O通道过早关闭,那么这不是一个有用的测试。
那么..尝试从deinit崩溃代码怎么样?
class B {
nop() { }
}
class A {
var b: B? = B()
deinit {
b = nil
b!.nop()
}
}
var a = A()
当deinit尝试通过nil引用访问函数时,程序应该以堆栈跟踪终止? (我假设)。
我可能会在某个时候尝试这个。目前我正在使用Xcode,但从命令行尝试也会很有趣。