NSWindowController and window release

Graham Cox

Here we go again… another memory management issue.

I have a fairly simple situation where I instantiate a window controller (NSWindowController subclass), which loads its window from a nib file. The window contains one custom view.

When the window is closed, the window controller (as its delegate) gets the -windowShould Close:, -windowWillClose: etc. as normal. The owner of the window controller (the app delegate in this case) retains it until it receives the -windowWillClose: notification, at which point it’s removed from its list of windows. Then, the window controller is deallocated, as expected.

However, the window it is controlling is never deallocated, and so neither is the custom view within it. The result is a lot of leaks.

I have been through the code with a fine-tooth comb, nothing that shouldn’t is retaining the window, nor the view.

There are no issues flagged up by running the analyser either.

The documentation for -[NSWindow releaseWhenClosed] states:

"The default for NSWindow is YES; the default for NSPanel is NO. Release when closed, however, is ignored for windows owned by window controllers. Another strategy for releasing an NSWindow object is to have its delegate autorelease it on receiving a windowShouldClose: message.”

In the nib ‘release when closed’ is set for the window, but apparently this is ignored for windows that have an associated windowController.

Following its advice, I tried autorelease-ing the window in the -windowShouldClose: method - result, EXC_BAD_ACCESS (whatever the state of the setting in the nib).

So what’s the deal - how do I get a window controller to let go of its window correctly?


Graham Cox

OK, I figured it out.

What was important to me was that the custom view was deallocated. Therefore it was the view’s -dealloc I was logging, not the window’s. I inferred, incorrectly, that it was the window that wasn’t going away. In fact it was, but the view wasn’t.

The custom view is set up as a layer hosting view, and I set the view to be the layer’s -layoutManager. That’s a strong property, so a retain cycle was created there.

Once understood, easily solved.

I do vaguely recollect something about this possibility in documentation a long time ago, but going through it just now, could find no mention of it. In the end, the only canonical documentation is the headers. Ho hum.


On 27 Jul 2017, at 9:39 pm, Graham Cox <graham@mapdiva.com> wrote:

Here we go again… another memory management issue.