macosstoryboardnswindowappkitnstabviewcontroller

How to exclude certain AppKit views from restorable NSWindow?


NSWindows can be made restorable so that their configuration is preserved between application launches.

https://developer.apple.com/documentation/appkit/nswindow/1526255-restorable

Windows should be preserved between launch cycles to maintain interface continuity for the user. During subsequent launch cycles, the system tries to recreate the window and restore its configuration to the preserved state. Configuration data is updated as needed and saved automatically by the system.

In a new macOS project, the NSWindow on a Storyboard is restorable by default:

Restorable checkbox in Xcode


My problem comes when embedding an NSTabViewController in the NSWindow.

NSTabViewController

The NSTabView is inheriting the window's restorable state automatically, with no added code.

This makes the selected tab persist between app launches. I don't want that. I want it to always default to index 0. If the selected tab is restored, attempting to select a tab programmatically in viewDidLoad has unexpected results.


How can I force certain AppKit UI elements to be excluded from NSWindow state restoration?

I want the Tab View to be un-restorable.

But I would like to keep other restorable benefits, such as restoring the previously-set window size.

How can single views be excluded from NSWindow state restoration?


Solution

  • The key to state restoration is the NSResponder method restoreStateWithCoder:

    This method is part of the window restoration system and is called at launch time to restore the visual state of your responder object. The default implementation does nothing but specific subclasses (such as NSView and NSWindow) override it and save important state information. Therefore, if you override this method, you should always call super at some point in your implementation.

    https://developer.apple.com/documentation/appkit/nsresponder/1526253-restorestate

    So, to not restore a certain control, make this method a no-op.

    It says that you "should always call super", but that restores the window state. So if you don't want window restoration, don't call super.

    In the case of a Tab View, it evidently must be done in the NSTabView (subclass) itself. In other views, overriding this method on the View Controller may work.

    class SomeTabView: NSTabView {
        
        override func restoreState(with coder: NSCoder) {
            // Do NOT restore state
        }
        
    }