OSX-Document-Modal-Dialogs-Sheets

How to Modally Present Windows as Sheets in OS X (Yosemite & Mavericks)

When developing iOS Apps it’s very rare to come up against a technical challenge that hasn’t already been solved and the solution shared on Stack Overflow or in Apple’s sample code in the iOS Dev Center. Unfortunately I haven’t experienced the same luxury with Mac OS X Development.

In a Mac App that I’m currently developing for a client I need to be able to create modally presented windows as sheets as described here in Apple’s Human Interface Guidelines.

sheet_example_2x

Document Modal Dialogs or “Sheets” are instances of NSWindow. According to Apple’s documentation to present a custom NSWindow sheet we use the following code:

[NSApp beginSheet: myCustomSheet
            modalForWindow: window
            modalDelegate: self
            didEndSelector: @selector(didEndSheet:returnCode:contextInfo:)
            contextInfo: nil];

Problem is beginSheet:modalForWindow:modalDelegate:didEndSelector:contextInfo: was deprecated a few years ago and appears to no longer work in Yosemite and Mavericks :-? With out-of-date documentation and all Googling resulting in out-of-date solutions to presenting custom modal windows, I went about figuring out the modern solution to this challenge!

The replacement for beginSheet:modalForWindow:modalDelegate:didEndSelector:contextInfo: is to now call beginSheet:completionHandler: on the NSWindow that you want to present from, passing in reference to the instance of your custom NSWindow subclass.

I also discovered a few important steps that you need to implement when presenting sheets…

Step 1: Retain a reference to the NSWindow or NSWindowController that you are creating when presenting a sheet:

@interface MainWindowViewController ()

@property (strong) CustomModalWindowController *myCustomModalWindowController;

@end

@implementation MainWindowViewController


- (IBAction)didTapOpenButton:(id)sender {
    self.myCustomModalWindowController = [[CustomModalWindowController alloc] initWithWindowNibName:@"CustomModalWindowController"];
   

    [self.window beginSheet:self.myCustomModalWindowController.window  completionHandler:^(NSModalResponse returnCode) {
       
    }];

   
}

@end

Step 2: Deselect the Visible at Launch window attribute for your custom NSWindow or it’ll fail to present modally

Visible-At-Launch

Step 3: Call the window “sheetParent” in order to close the sheet and trigger the sheet completion block in the presentation code:

[self.window.sheetParent endSheet:self.window returnCode:NSModalResponseOK];

I’ve created a demo Xcode project that you can grab from my github repository to see this all in action:

Download source example from Github

Happy Coding!

It's only fair to share...Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedInShare on StumbleUpon