Swift: no output for println in deinit method (not using playground)

This is my test code (run in the terminal):

#!/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)

Output:

  • UIImagePickerController on iPad with IOS9
  • All IBOutlets become nil after switching to Xcode 6 Beta 5
  • Pass multiple parameters to addTarget
  • Objective-C/Cocoa: Detect all keypresses
  • IBOutlets and IBactions require ! in the end
  • How do I know how to conform to a specific protocol in Swift?
  • 1
    A deinit
    0
    

    There is no output “A deinit” if the line mentioned above is commented out. And the output will be:

    1
    1
    

    I’ve used swiftc to compile the code but the result is still the same. (xcrun swiftc -o test test.swift)

    Is it by design that the stdout will be closed when the program exits, or the objects are still referred (by what?) when they are destructed?

    Update: Thanks to @Logan , now I have more details about it.

    When it is run inside a function, it will output A deinit even if I comment out a = nil:

    #!/usr/bin/xcrun swift
    
    class A {
        deinit {
            println("A deinit")
        }
    }
    
    func test() {
        var a: A? = A()
        //a = nil
    }
    
    test()
    

    I’m not using a playground in Xcode. :-$

    Update

    #!/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()
    

    Result: No output to stdout or the file, unless running in the test function.

    2 Solutions Collect From Internet About “Swift: no output for println in deinit method (not using playground)”

    While I don’t see an explicit reference that says “Swift’s deinit has exactly the same semantics as ObjC’s dealloc,” it is hard to imagine that this isn’t true, since Swift and ObjC objects are both managed by ARC and generally speaking interchangeable.

    Given that, this is exactly expected. Cocoa does not deallocate objects at program termination. It just terminates, leaks all the memory, file handles, and other system resources, and leaves it to the OS to cleanup. This makes program termination dramatically faster than it would be otherwise.

    This is an important point because it means you generally should not use deinit to manage anything other than OS-managed resources (certainly not anything that you require to run). Of course, there’s no way to guarantee that a destructor runs, even in C++. If you crash, it won’t happen, and your program would have to deal with that. You can think of it as all Cocoa programs quietly crashing when they terminate.

    So in your case, a = nil is causing deinit to be run, while program termination does not.

    The program is exiting and you wonder if there’s a race (e.g. Swift implementation bug) in the early Swift implementation. Exit handlers should definitely be called at normal program exit (as opposed to SIGKILL).

    I’d suggest creating a file in deinit and checking for its presence after the program exits, but if I/O channels are getting closed prematurely as you speculated, that isn’t a useful test.

    So .. how about trying to crash your code from deinit instead?

    class B {
         nop() { }
    }
    
    class A {
         var b: B? = B()
         deinit {
             b = nil             
             b!.nop()
         }
    } 
    
    var a = A()
    

    When deinit trys to access a function through a nil reference, the program should terminate with a stack trace? (I assume).

    I might experiment with this at some point. Currently I’m using Xcode but it would be fun to try from command line too.