Deinit not being called in ChatWindowController

Hello,

I wanted to trace through the removal of the observer from the NSNotificationCenter so I placed a println in and a breakpoint on the deinit method of the ChatWindowController class. However I noticed that when I closed the the Chatter window deinit was not being called. After reading more about the deinit method in Swift and thinking about the problem I summarized that the issue might be that the ChatWindowController instance was not being removed from the ChatWindowController array that is held in the AppDelegate. I double checked the text in the book to see if I missed adding in that functionality but there wasn’t any such discussion. I added the following method to AppDelegate:

[code] func removeWindowController(windowController: ChatWindowController) {
var index = find(windowControllers, windowController)

    if index != nil {
        windowControllers.removeAtIndex(index!)
    }
}

[/code]
I also had the ChatWindowController class adopt the NSWindowDelegate protocol so that it could be notified when the window is closing by implementing windowWillClose(notification: NSNotification). Here’s the implementation of that method in ChatWindowController:

func windowWillClose(notification: NSNotification) { print("Window will close") let appDelegate = NSApplication.sharedApplication().delegate as! AppDelegate appDelegate.removeWindowController(self) }
It retrieves the App delegate using the sharedApplication method on NSApplication. Once the AppDelegate has been retrieved the removeWindowController method on it that was described earlier is invoked.

With these changes in place, the deinit method on the ChatWindowController is now called and the observer is unsubscribed from the NSNotificationCenter.

Regards,
Rob

Thanks for sharing this, Rob. Definitely a helpful exercise for understanding all the pieces involved and the architecture of the app.

I wanted to make two suggestions. The first is a minor Swift style bit. Instead of making a variable and testing it for nil, use if-let and avoid the optional variable and forced unwrapping:

    func removeWindowController(windowController: ChatWindowController) {
        if let index = find(windowControllers, windowController) {
            windowControllers.removeAtIndex(index)
        }
    }

The other is a Cocoa design suggestion. The window controller is a logical place to listen for NSWindowWillCloseNotification, however it introduces some undesirable coupling for the window controller to know about the AppDelegate.

In this case I would suggest instead that the AppDelegate observe NSWindowWillCloseNotification: add itself as an observer when showing the window, then removing the window controller from the array (and removing itself as an observer) upon receiving the notification. This way the window controller doesn’t need to know about the AppDelegate, or that the AppDelegate is even keeping a reference to it.

In Swift 2.1, I think you need to use following:

if let index = windowControllers.indexOf(windowController) { windowControllers.removeAtIndex(index) }