Swift:在deinit方法中没有println的输出(不使用playground)

时间:2014-11-20 16:25:55

标签: macos swift xcode6

这是我的测试代码(在终端中运行):

#!/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,或者当它们被破坏时仍然引用对象(通过什么?)?

更新:感谢@Logan,现在我有更多详细信息。

当它在函数内运行时,即使我注释掉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或文件。

2 个答案:

答案 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,但从命令行尝试也会很有趣。