Restoring multi-windowed documents on Lion

Lion introduces a new feature called window restoration, whereby when relaunching an app, it comes back just as you left it. Plenty of people across the internets seem upset by it, but I happen to love it.

Happily, document-based apps — without any extra effort — get restoration of document windows for free! Quitting and relaunching will reopen any previously open documents, almost as if by magic, even if you haven't yet adopted autosave-in-place behaviour. This seems to anger some internet people even more.

But what if your document happens to have multiple windows, some of them optional? We have exactly that in Sandvox: there's a main document window, but optionally, extra windows associated with the doc for Code Injection. We were trying to tighten up Sandvox's window restoration to include such windows, and frankly it's a mystery to fathom! The aforementioned restoration-haters make it even harder, by occupying most of the search results. Fortunately we battled through and found the answer:

This method is not in the documentation (rdar://problem/10437425), but is in the headers, and it's the key to the whole thing:

@interface NSDocument (NSRestorableState)

- (void)restoreDocumentWindowWithIdentifier:(NSString *)identifier state:(NSCoder *)state completionHandler:(void (^)(NSWindow *, NSError *))completionHandler NS_AVAILABLE_MAC(10_7);

@end

Find it in NSWindowRestoration.h for full details.

For most apps it already does the right thing, as witnessed by the way doc windows automatically restore. To handle optional, secondary windows takes a little more work though. Here's a rough version of the solution we arrived at in Sandvox:

The important thing to note is that Cocoa's standard behaviour only knows how to create document windows by calling -makeWindowControllers. Anything more advanced, such as here, and you have to override to create it yourself.

The final piece of the puzzle then, is how to give your secondary window a unique identifier. We tried to do this in Interface Builder, but found that went ignored for some reason. Something as simple as this works pretty well:

(Out of the box, all document windows get given the same identifier by the system)

© Mike Abdullah 2007-2015