Deinit is not called from main code

I have a problem, where deinit is not called in main code of a command line tool. Here is an example:

import Foundation
class CmyClass {
    private var foo : String
    init(_ s : String) {
        foo = s
        print("x: init \(foo)")
    }
    deinit {
        print("x: deinit \(foo)")
    }
}

do {
    let mc = CmyClass("called in do scope")
}

let mc1 = CmyClass("called in main")
exit(0)

This gives the output

x: init called in do scope
x: deinit called in do scope
x: init called in main
Program ended with exit code: 0

So the deinit is not called if there is no additional scope.
Is it a bug or a feature?

TIA,

GreatOm

PS. I use Xcode 12.5 on macOS 11.4

This is expected behavior. Cleanup of memory is not required when the process is about to exit.

1 Like

Ok. Thanks for clarification.

There was a related discussion here a few months back that delves deeper into this behavior and the reasoning behind it.

2 Likes

So if a class wraps around external stuff, and needs extraordinary cleanup, the docs for that class has to specify that, that class needs to be inside a scope?

There is no way to absolutely guarantee this. Regardless of what the language does, your process can be killed by the OS at any time, and this is standard policy on many platforms Swift targets—iOS will kill processes when their app is idle (and macOS too if you opt into sudden app termination, which is strongly recommended), and Linux will summarily kill processes when it runs out of memory. If you have cleanup needs that aren't covered by process teardown, you have to be ready to deal with that cleanup potentially not happening.

4 Likes