Presenting modal dialogs from XIB in Cocoa: best/shortest pattern?
cocoa, modal-dialog, nswindowcontroller, objective-c, xib
Solution
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.
Problem
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.