2

Right now I have an OS X storyboard app that has a main window, and a button on it that triggers a "show" segue for another view controller. Right now I've got the segue set up as modal because if I don't, the user could click the same button again and end up with two copies of the same window.

Is there a way for me to accomplish this without having to restructure the storyboard to embed these view controllers in a separate window controller (which would seem to defeat the purpose of the flexibility the storyboards offer)?

Aaron
  • 879
  • 7
  • 18

1 Answers1

18

Edit: While the answer below does work, it is definitely not the best way. In your storyboard, select the view controller for the destination view then go to the attributes inspector and change Presentation from Multiple to Single. That's it, no code required.

view controller presentation attribute


Not sure this is the best way but in the NSViewController that is pushing the segue, you could add a property for the destination NSViewController and, in your prepareForSegue:sender: method, assign the destination view controller. Finally, in the shouldPerformSegueWithIdentifier:sender: method, check to see if the destination view controller is assigned, and, if so, bring its window to the front and return NO meaning don't perform the segue, otherwise, return YES. Here's a quick example (to be included in the NSViewController with the button to initiate the segue):

@interface ViewController ()
@property (weak) NSViewController *pushedViewController;
@end

@implementation ViewController

- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender {
    if (self.pushedViewController) {
        [self.pushedViewController.view.window makeKeyAndOrderFront:self];
        return NO;
    }
    return YES;
}

- (void)prepareForSegue:(NSStoryboardSegue *)segue sender:(id)sender {
    self.pushedViewController = segue.destinationController;
}

@end

When you close the window containing the destination view controller, this will set the pushedViewController property of the original view controller to nil so the segue will perform if the window is not already opened. Again, there may be a better way to do this. Hope this helps.

Jon

Jon
  • 1,469
  • 1
  • 14
  • 23
  • 1
    I've always wondered what the "presentation" setting was for. Thanks so much! – Aaron Mar 20 '16 at 23:48
  • Thanks; this was what I needed. An additional twist: you have to set the presentation on the target of your segue. If you use the ViewController out of the box, you need to set _it's_ presentation; if you assign a WindowController, you need to set that. – green_knight Oct 13 '17 at 18:28
  • @JoeySlomowitz I'm not sure but why would you want to? The point of using the storyboard is you get all the functionality for free without code. Simply connect the action of a button to the `Show` method of the pushed view, set the presentation to single and you're done. What is the use case for sometimes presenting one view and other times multiple instances? – Jon May 09 '20 at 20:09
  • @Jon The requirements and infrastructure in my project is set up to not use storyboards so I need a programmatic solution. – Joey Slomowitz May 10 '20 at 00:06
  • @JoeySlomowitz This question and answer are specifically about the use of storyboards. If you are looking to push a window without using storyboards, simply call `makeKeyAndOrderFront:` on your pushed window. If this doesn’t help, you should post a question as opposed to pursuing this in the comments for this answer. – Jon May 11 '20 at 01:10