On Mar 3, 2016, at 05:27 , Bill Cheeseman <wjcheese...@gmail.com> wrote:
> 
> I use MainWindowController as the restoration class:
> 
>    static func restoreWindowWithIdentifier(identifier: String, state: 
> NSCoder, completionHandler: (NSWindow?, NSError?) -> Void) {
>        let controller = MainWindowController()
>        var restoreWindow: NSWindow? = nil
>        if identifier == "MainWindow" {
>            restoreWindow = controller.window
>        }
>        completionHandler(restoreWindow, nil);
>    }
> 
> However, how do I fit this into the storyboard context? When I create an 
> instance of MainWindowController here, I seem to be bypassing the segues in 
> the storyboard. It occurs to me that maybe I should make AppDelegate the 
> restoration class, instead of MainWindowController. The documentation is 
> cryptic, even in the NSWindowRestoration.h header file comments. I'm thinking 
> that then I could just restore the previously encoded underlying data model 
> values and let the storyboard run by itself as usual. But it isn't clear to 
> me what will become of the temporary window controller. Or, in other words, 
> how do I find or create a valid window in this method, as the header file 
> comments say I should?

— There’s nothing wrong with using MainWindowController as your restoration 
class (AFAIK), because the restoration method is a static func.

OTOH, there’s no particular reason, in *this* part of the restoration 
mechanism, to tie restoration to the window controller at all. In a sense, the 
window controller has nothing to do with it, except to the extent that the 
timing of its instantiation determines the time of window loading.

There may be other reasons to tie restoration to the window controller. I’ll 
come back to that point later.

— Ignoring the rest of your app for a moment, if you’re using a storyboard then 
creating a naked MainWindowController here is the wrong thing to do. Instead, 
instantiate a MainWindowController from the storyboard in the “usual” way:

>       let storyboard = NSStoryboard (name: "MainStoryboard", bundle: nil)
>       let controller = storyboard.instantiateControllerWithIdentifier (“Main 
> Window Controller") as! MainWindowController

This isn’t a *temporary* window controller, it’s the real thing. That means the 
next step is to store the window controller reference wherever your app 
normally keeps that reference: perhaps as a property of the app delegate. 
Lastly, you invoke the completion handler to complete the window restoration 
process (the controller.window reference causing the window to be loaded as 
usual).

— But you need to be aware of what the rest of your app is doing at startup. If 
your ‘main’ function instantiates the window controller unconditionally, then 
you don’t want to instantiate a second one. You have a couple of choices of 
what to do. You can go ahead and create it as you do now, then have your state 
restoration static func *find* the window and initiate restoration on that. 
(That’s what the header file comment "It is acceptable to invoke the completion 
handler with a pre-existing window…” means: legacy code might have created the 
window already, and you might wish not to change that.) Your restoration method 
wouldn’t actually create anything in that case.

In these circumstances, it might indeed make sense to use the app delegate as 
the restoration class, especially if it’s storing a pointer to the window 
controller privately anyway.

Or you can remove that initial instantiation, leave the controller 
instantiation in the state restoration static func as above, check (in 
application didFinishLaunching) to see if a window controller exists due to 
state restoration, and create it if not. This sounds like an excess of trouble, 
but it’s what you’d do if you want to get to state restoration *before* the 
window was actually loaded, for example if you wanted to create one of a number 
of different NSWindow subclasses depending on state.

— Back to window controllers. If you have no custom state restoration, I think 
I’d put the state restoration code in the app delegate and be done with it. 
Looking back at the code in an old project, I see that’s what I did with the 
preferences window, even though it’s document-based application. In the app 
delegate (Obj-C because it’s old):

>       NSWindow* window = nil;
>       
>       if ([identifier isEqualToString: @"GRAPreferencesWin"])
>               window = [GRAPrefWinController sharedWindowController].window; 
> // creates the window controller if it does not exist
>       
>       completionHandler (window, nil);


However, if you do have custom state restoration, then I think it’s easier to 
put methods like encodeRestorableStateWithCoder and restoreStateWithCoder in 
the window controller, since there is going to be a custom class anyway. 
Otherwise, you’d have to subclass NSWindow, and put what I think of as 
controller logic in the window instead of the controller.

In *this* configuration, it might make sense to put restoreWindowWithIdentifier 
in the window controller class after all, to keep all the related code together.

I agree with you that this is poorly documented and under-documented. In a 
document-based app, some important parts of the process happen automatically in 
NSDocumentController. In most cases, though, it’s very little code, if only you 
can work out where to put it.

_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to