views:

560

answers:

3

I'm trying to show a NSPanel as a sheet. I'm naively doing something along those lines:

SheetController *sheetController = [[[SheetController alloc]
                                      initWithWindowNibName:@"Sheet"] autorelease];

[[NSApplication sharedApplication] beginSheet:sheetController.window 
                               modalForWindow:self.window
                                modalDelegate:self
                               didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) 
                                  contextInfo:nil];

For some reason that eludes me, this isn't working. When this part of the code is called, the sheet momentarily flashes (because of the autorelease message). The sheet is never hooked to window.

If anyone can point me to where I can find more information, that would be very appreciated.

+2  A: 

Yes, you need to own this controller for as long as you want it to continue functioning. You can't just create it, autorelease it, and let it die—you need to hold onto it for as long as you need it.

Peter Hosey
While removing the autorelease message prevents the panel from disappearing, it is still not hooked to the window... I'm really perplexed by this.
Martin Cote
It's not enough to simply not autorelease it. That's just a leak. You need to own what you have created, and release it when you're done with it (and *only* then). As for hooking up the controller to the window it controls, you must make sure you've set the class of the File's Owner, then connect your controller's `window` outlet to the window. You do both of those in IB.
Peter Hosey
+2  A: 

This sounds like a classic case of having checked the "Visible at Launch" box for the panel in IB. Turn that off.

Mike Abdullah
Spot on! Many thanks.
Martin Cote
A: 

Don't forget that if you're trying to run this as a "modal" sheet (i.e. it takes over the app until the user dismisses it), you'll need to push a new run loop.

What you've done is shown the sheet, and then not pushed a new loop, so the OS just shows the sheet, sees there's no reason to keep it running, and thus shuts it down and resumes execution on the next line:

I typically do sheets the following way:

- (id)showPanelModalAgainstWindow: (NSWindow *)window
{
   [[NSApplication sharedApplication] beginSheet: panelToShow
                modalForWindow: window
                modalDelegate: self
                didEndSelector: @selector(sheetDidEnd:returnCode:contextInfo:)
                contextInfo: nil];

   [[NSApplication sharedApplication] runModalForWindow: panelToShow];
   if (m_returnCode == NSCancelButton) return nil;
}


- (void)sheetDidEnd:(NSWindow *)sheet
         returnCode:(int)returnCode
        contextInfo:(void  *)contextInfo
{
    UNUSED(sheet);
    UNUSED(contextInfo);
    m_returnCode = returnCode;
}

Then, in your accept and/or cancel button routines:

- (IBAction)continueButtonClicked:(id)sender
{
    UNUSED(sender);
    [[NSApplication sharedApplication] stopModal];
    [createAccountWizardPanel orderOut: nil];
    [[NSApplication sharedApplication] endSheet: createAccountWizardPanel
                                       returnCode: NSOKButton];

}

I'm sure there is a slightly less code-y way of doing this, but I've not looked to deeply into it, because this way works perfectly fine thus far ....

Previous comments about the lifetime of the controller and panel objects are also relevant -- be sure to understand exactly what objects you need for what lifetimes when showing a modal panel.