I have used NSWindowController in projects several times, and feel like I have a (very)rough grasp of the concepts behind this important class. What I would like to do with this post is to clarify/correct my own understandings, and hopefully help other learners get that first step into understanding. It's the at-a-glance concepts, overview, and best practices that I find is most useful, and often lacking in the documentation. Here is my take on NSWindowController (questions are interspersed in bold):
- An NSWindowController (NSWC) subclass exists (conceptually) just beneath every window nib, acting as the glue between the user interface elements and the model objects that they control/represent. Basically, every window in your application should have its own NSWC subclass.
- The File's Owner of the nib should always be the NSWC subclass. Is this the case even for the MainMenu.xib application?
- The NSWC
window
property should always be linked to the NSWindow in InterfaceBuilder. - You should override the 'init' method, using
[super initWithWindowNibName:]
, so that when you refer to[mycontroller window]
it will load the nib. Should this also be the case for the NSWC for the MainMenu.xib window, even though this is opened at startup? - The NSWC shouldn't do too much heavy lifting - it should simply pass messages to instances of objects, and present those objects in the UI.
- It can modify the UI using binding, or acting as a delegate for tables etc., or by actively changing the UI elements when it observes a change, or a combo of any of the above (which one you use seems to be a matter of taste, with pros and cons on all sides).
- An NSWC can create instances of other NSWCs when necessary (for example, when opening a one-off sub-window).
Use the
[mycontroller showWindow:nil]
to display the associated window at the front. If you want the window to appear as a sheet, use something like:NSWindowController* mycontroller = [[MyController alloc] init]; [NSApp beginSheet: [mycontroller window] modalForWindow: [self window] modalDelegate: self didEndSelector: @selector(didEndMySheet:returnCode:contextInfo:) contextInfo: nil];
The didEndSelector:
should be a method of the NSWC of the parent window, and can access and release 'mycontroller' with [sheet windowController]
.
- To close the window call the performClose:
method of NSWC's window.
Some Questions:
- Should the NSWC of the MainMenu window also be the application delegate, or should this be a different class?
- In the same vein, should the main NSWC handle files (drag/drop and opening), or should it be passed on to the app delegate, or is that just a matter of taste?
Please correct me if any of this is bad practice, or is just plain wrong. I am looking to clarify my understanding of NSWindowController, so any additions (in the form of best practices, experiences, gotchas) would be highly appreciated.
Thanks, Laurie