Search code examples
cocoareleasenswindowdeallocnswindowcontroller

Cocoa NSWindowController And NSWindow Not Deallocing


I'm working with an NSWindowController to implement a preferences window. Apple's documentation states that by default the controller and window aren't deallocated, because it's useful to not have to reload everything, which makes sense. But their documentation goes on to say that you can override that behavior, but not explain how.

Apple's Docs:

When a window is closed and it is part of a document-based
application, the document  removes the window’s window
controller from its list of window controllers. This results 
in the system deallocating the window controller and the
window, and possibly the NSDocument object itself. When a
window controller is not part of a document-based application, 
closing the window does not by default result in the
deallocation of the window or window controller. This is the
desired behavior for a window controller that manages something
like  an inspector; you shouldn’t have to load the nib file
again and re-create the objects the  next time the user requests
the inspector.

If you want the closing of a window to make both
window and window controller go away when it isn’t
part of a document, your subclass of NSWindowController
can observe the NSWindowWillCloseNotification notification
or, as the window delegate, implement the windowWillClose: method.

I can't find anywhere that explains what to "implement" in the windowWillClose: method.

The window controller can be seen here: https://github.com/gngrwzrd/gwpreferences/blob/master/GWPreferences/GWPreferences/GWPreferences/GWPrefsWindowController.m

Using the controller can be seen here: https://github.com/gngrwzrd/gwpreferences/blob/master/GWPreferences/GWPreferences/GWAppDelegate.m - you can see in this code where I'm trying some bridge casting to try and force release objects but it doesn't work.

So the GWPrefsWindowController.dealloc method never gets called. Any ideas?


Solution

  • I understand this question is old, but for those who came here from google, the answer is quite simple.

    As stated in the documentation, for non document base applications, you can simply:

    • Keep a reference for your NSWindowController wherever your are calling it. (In the example below it's referenced by myWindowController;
    • Make the class calling your NSWindowController implement the protocol NSWindowDelegate;
    • Release your Window Controller by setting it to nil on windowWillClose: method

    To answer the question more precisely. When lazy instantiating your controller, set your class as the delegate:

    -(IBAction)showMyWindowAction:(id)sender
    {
        // If my window controller is not nil
        if (!myWindowController)
        {
            //instantiate it
            myWindowController = [[MyWindowController alloc] initWithWindowNibName:@"myWindow"];
            // set your class as delegate
            [myWindowController setDelegate:self];
         }
    
         [myWindowController.window orderFront:self];
    }
    

    And then implement the windowWillClose: method from the NSWindowDelegate protocol

    -(void)windowWillClose:(NSNotification *)notification
    {
         //Check if it's the right window that will close
         if ([notification.object isEqualTo:myWindowController.window])
         {
             //Set your controller to nil
             myWindowController = nil;
          }
    }
    

    That's it, your window controller will now dealloc and since we are verifying if it's controller is nil before showing the window, everything will work!

    I believe the reason why this is not implemented by default is because the initWithWindowNibName: is a somewhat heavy operation, and thus you have to think if dealloc'ing whatever is on your window will impact more or less than loading your window nib file.

    I hope it helped