I decided to give storyboards on Mac a try again in this little project. Typically, if my app has all windows closed and the user clicks the icon in the dock, I have my app show the "main window" in my app.
This little project is a shoebox app. Normally, I'd have my app delegate create the main window controller in app did finish launching. Something like this:
-(void)applicationDidFinishLaunching:(NSNotification*)aNotification
{
self.windowController = [[WindowContorller alloc]init];
[self.windowController showWindow:nil];
}Then in -(BOOL)applicationShouldHandleReopen:(NSApplication*)sender hasVisibleWindows:(BOOL)flag, if necessary, call showWindow on main window controller again.
In a storyboard, you cannot connect an outlet from the App delegate scene to the initial window controller. So I'm instantiating it programmatically:
-(void)applicationDidFinishLaunching:(NSNotification*)aNotification
{
NSStoryboard *storyboard = [NSStoryboard storyboardWithName:@"Main" bundle:nil];
self.windowController = [storyboard instantiateInitialController];
}Then in applicationShouldHandleReopen:hasVisibleWindows: I do what I normally do. For whatever reason, I am sometimes getting multiple instances of my initial window controller. I changed the presentation to "Single" on the window controller in the storyboard but I'm still getting multiple instances.
"Single" vs. "Multiple":
In a NSDocument-based app, you want to create a new window controller (and window) for each document that's opened, so you want "multiple" instantiation in the storyboard.
In a shoebox app, you want always to get back to the main window, so you want "single" instantiation in the storyboard. In this case, when something causes instantiation of the window scene, the storyboard checks whether the window exists and is or isn't visible, and either (re-)creates it or show it accordingly. (The behavior is a little bit broken on macOS, at least with NSPanel windows, but the principle still applies.)
>> Or do you always have to turn off the the initial controller for every project?
The point of an initial controller is just an automatic instantiation when the storyboard is instantiated through the parameterless method. In the special case of the main storyboard (the one that's referred to by the info.plist file, or equivalently the mina storyboard setting on the project's General tab in Xcode), the storyboard is also instantiated automatically, giving the automatic window controller instantion also for free. It's basically a convenience, and it's fine (if unnecessary, mostly) to arrange the code to do either of these things manually if you prefer.
Back in Feb, your original problem was just that you were instantiating manually when it was already being done automatically as a convenience. As you discovered, you just needed to do one or the other, not both.
However, instead of turning off the automatic behavior in the main storyboard, I would recommending changing the workflow to leave the app delegate out of it (and eliminate its "windowController" property). Instead, in your window controller subclass, create a static property called something like "shared" that's the main window controller, and set it to the actual window controller in windowDidLoad (preferably) or the designated window controller init (if you have to). You can declare this property get/set(private), so that it's read-only outside the window controller subclass. Anything that current goes to the app delegate "windowController" property can go to WindowController.shared instead.
Alternatively…
It's not ridiculous to take your window scene (and its related view subscenes) out of the main storyboard, and putting them in their own storyboard. This is perhaps especially appropriate if you have multiple window types in your shoebox app, and you want to use a different storyboard for each window, to keep the IB complexity down a bit.
In that case, you would manually instantiate the various storyboards as needed, presumably the main one in "applicationDidFinishLaunching:" and the other ones as the result of menu item actions, with the window controller scenes set as "single" and "initial controller" in each storyboard. (Then you can use the simple storyboard instantiation function and don't need to know the storyboard IDs in your code.)
Finally…
In a shoebox app, you should typically not have a "close" function for the main window. (There's a checkbox for this in the window attribute inspector in IB.) Otherwise, closing the window gives you an app whose entire UI is its menu bar, and users find that extremely confusing. Better to keep the main window open, and all of the re-instantiation issues just go away as a side benefit.
Does that cover everything? I think so.