What is the correct way to make a NSWindowController Singleton in Swift?

968 Views Asked by At

I have a sample project as:

https://github.com/ericgorr/nspanel_show.git

My project is a storyboard, document based application. I would like to use a custom segue to toggle the visible state of the inspector window. What I have should work, but I cannot quite determine how to make the inspector window a singleton.

I believe I should start with:

class InspectorWindowController: NSWindowController
{
    static let sharedInstance = InspectorWindowController()

//    override func init()
//    {
//        
//    }

    override func windowDidLoad()
    {
        super.windowDidLoad()

        NSLog( ":::: %@", InspectorWindowController.sharedInstance );
    }
}

But exactly what the initialization should look like in my situation is escaping me, especially since the window is inside of a storyboard.

2

There are 2 best solutions below

1
On

Here's how I would modify your code:

  1. In Main.storyboard give your InspectorWindowController an identifier, such as "Inspector Window Controller"
  2. In InspectorWindowController, implement your singleton as follows:

    static let shared: InspectorWindowController = {
        let storyboard = NSStoryboard(name:"Main", bundle: nil)
        let controller = storyboard.instantiateController(withIdentifier: "Inspector Window Controller")
        return controller as! InspectorWindowController
    }()
    
  3. In Main.storyboard delete the segue from WindowController to InspectorWindowController

  4. In WindowController replace the showMyPanel() and hideMyPanel() IBActions with:

    @IBAction func toggleInspectorPanel( _ sender: AnyObject ) {
        let inspectorWindow = InspectorWindowController.shared.window!
        if inspectorWindow.isVisible {
            inspectorWindow.orderOut(self)
        } else {
            inspectorWindow.makeKeyAndOrderFront(self)
        }
    }
    
  5. Also in WindowController, remove the NSLog() call from windowDidLoad(). It causes a recursive call to the InspectorWindowController.shared initialization code.

  6. In Main.storyboard link the Inspector toolbar button to toggleInspectorPanel()

The InspectorWindowController.shared singleton will be initialized, and the inspector panel loaded (but not shown), the first time it is referenced.

0
On

You can select the window controller from the window controller scene and in the attributes inspector select Single from the pop up under Presentation. This will ensure the show segue only uses a single instance of the window controller. See this answer for more information.