Presenting modal dialogs from XIB in Cocoa: best/shortest pattern?

2.4k views Asked by At

Below is my typical WindowController module for presenting a modal dialog (could be settings, asking username/password, etc) loaded from a XIB. It seems a bit too complex for something like this. Any ideas how this can be done better/with less code?

Never mind that it's asking for a password, it could be anything. What frustrates me most is that I repeat the same pattern in each and every of my XIB-based modal window modules. Which of course means I could define a custom window controller class, but before doing that I need to make sure this is really the best way of doing things.

#import "MyPasswordWindowController.h"

static MyPasswordWindowController* windowController;

@interface MyPasswordWindowController ()
@property (weak) IBOutlet NSSecureTextField *passwordField;
@end

@implementation MyPasswordWindowController
{
    NSInteger _dialogCode;
}

- (id)init
{
    return [super initWithWindowNibName:@"MyPassword"];
}

- (void)awakeFromNib
{
    [super awakeFromNib];
    [self.window center];
}

- (void)windowWillClose:(NSNotification*)notification
{
    [NSApp stopModalWithCode:_dialogCode];
    _dialogCode = 0;
}

- (IBAction)okButtonAction:(NSButton *)sender
{
    _dialogCode = 1;
    [self.window close];
}

- (IBAction)cancelButtonAction:(NSButton *)sender
{
    [self.window close];
}

+ (NSString*)run
{
    if (!windowController)
        windowController = [MyPasswordWindowController new];
    [windowController loadWindow];
    windowController.passwordField.stringValue = @"";
    if ([NSApp runModalForWindow:windowController.window])
        return windowController.passwordField.stringValue;
    return nil;
}

The application calls [MyPasswordWindowController run], so from the point of view of the user of this module it looks simple, but not so much when you look inside.

1

There are 1 answers

1
Ken Thomases On BEST ANSWER

Set tags on your buttons to distinguish them. Have them both target the same action method:

- (IBAction) buttonAction:(NSButton*)sender
{
    [NSApp stopModalWithCode:[sender tag]];
    [self.window close];
}

Get rid of your _dialogCode instance variable and -windowWillClose: method.

-[NSApplication runModalForWindow:] will already center the window, so you can get rid of your -awakeFromNib method.

Get rid of the invocation of -[NSWindowController loadWindow]. That's an override point. You're not supposed to call it. The documentation is clear on that point. It will be called automatically when you request the window controller's -window.

Get rid of the static instance of MyPasswordWindowController. Just allocate a new one each time. There's no point in keeping the old one around and it can be troublesome to reuse windows.