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

This is my test code (run in 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:

1
A deinit
0

      

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

1
1

      

I used swiftc

to compile the code, but the result is still the same. ( xcrun swiftc -o test test.swift

)

Is the default design that stdout will be closed when the program exits, or will objects still be passed (what?) When they are destroyed?

Update: Thanks to @Logan, I now have more details on this.

When it runs inside a function, it outputs A deinit

, even if I comment a = nil

:

#!/usr/bin/xcrun swift

class A {
    deinit {
        println("A deinit")
    }
}

func test() {
    var a: A? = A()
    //a = nil
}

test()

      

I am not using 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 file, unless it works in test

.

+3


source to share


2 answers


Until I see an explicit reference that says "Swift deinit

has exactly the same semantics as ObjC dealloc

", it is hard to imagine that this is not the case, since Swift and ObjC objects are both ARC driven and generally interchangeable.

Given this, this is definitely expected. Cocoa does not deallocate objects at program termination. It just shuts down, leaks all memory, files and other system resources and goes to the OS to clean up. This significantly shortens the life of the program than otherwise.



This is an important point because it means that you shouldn't use deinit

anything other than OS-managed resources to manage anything at all (not everything you need to run, of course). Of course there is no way to guarantee that the destructor works, even in C ++. If you crash, it won't, and your program will have to deal with it. You can think about this, since all Cocoa programs quietly crash on completion.

So, in your case, a = nil

triggers startup deinit

while program termination is not in progress.

+7


source


The program ends, and you wonder if there is a race (like a Swift implementation bug) in an early Swift implementation. Output handlers must be called on normal program exit (as opposed to SIGKILL).

I suggest creating the file in deinit and checking for its presence after the program exits, but if the I / O pipes are closed prematurely as you suggested, this is not a useful test.

So how about rolling your code with deinit instead?



class B {
     nop() { }
}

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

var a = A()

      

When deinit tries to access a function via a nil reference, should the program exit with a stack trace? (I guess).

I might experiment with this at some point. I am currently using Xcode, but it would be nice to try from the command line as well.

0


source







All Articles