TheDarkKnight TheDarkKnight - 4 months ago 25
Swift Question

Understanding Retain count in an AppDelegate

Within an application, I'm wondering why an instance of a class's

deinit
method is not being called when quitting the application.

As an example, the Test class presented here is created in the AppDelegate's
applicationDidFinishLaunching
.

import Cocoa

class Test {
let testVar = 1

init() {

print("Retain count \(CFGetRetainCount(self))")
NSApplication.shared().terminate(self)
}

deinit {
print("Calling deinit")
}
}


@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

//@IBOutlet weak var window: NSWindow!

func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application

_ = Test()
}

func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application

print("Terminating")
}
}


Not only does this fail to call Test's
deinit
method, but the retain count in Test's
init
is 2; I would have expected this to be 1.

If an optional reference is stored in the AppDelegate class and set when creating the Test instance, it is nil when
applicationWillTerminate
is called

Can someone please explain why the retain count is 2 here and how to ensure that deinit of Test is called when the application is terminated?

Answer Source

The issue is due to terminating the application from within the init of the Test class. I suspect that calling terminate in the init is preventing the correct instantiation of the class, so its deinit is never called.

By delaying the call to terminate, the call to Test's deinit is called, as expected

import Cocoa

class Test {

    init() {

        DispatchQueue.global().asyncAfter(deadline: .now() + 1.0) {
            NSApplication.shared().terminate(self)
        }
    }

    deinit {
        print ("Calling Deinit")
    }
}


@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    //@IBOutlet weak var window: NSWindow!
    var variable: Test?

    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // Insert code here to initialize your application

        variable = Test()

    }

    func applicationWillTerminate(_ aNotification: Notification) {
        // Insert code here to tear down your application

        variable = nil
        print("Terminating")
    }
}