Beyond Scripting in Swift: A preference sheet

In my original plan, I had hoped to get some of the new features destined for Consolation 3 up and running before building on the GUI to support them. But these rely on changing the app’s preferences, something which is fraught from outside the app because of the way that macOS handles preferences.

In this situation, the best way for the user (and developer) to edit preferences is by making a drop-down preference sheet, which is encapsulated in a new view controller with its own class: Prefs View Controller.

With the main storyboard open in Xcode, drag and drop an instance of a View Controller onto a free area below the main view controller, to create the sheet. If you want to at this stage, you can add some of the controls you are going to need in the preferences, but the one important control which you must add before trying to run this is a Close or OK button to dismiss the sheet.



Then add a new Cocoa Class to the project using the New / File menu command. Name it PrefsViewController, ensure that it is a subclass of NSViewController, don’t create a XIB file for it, and stick with Swift as the language.



Associate this View Controller with its new class by selecting the View Controller in the left panel of the storyboard editor, then in the right side of the window show the Identity Inspector. Set its Custom Class to PrefsViewController, and set the Storyboard ID and Restoration ID to prefsViewController.


Before going any further, make an Action for your Close button which will close the sheet, in the new PrefsViewController.swift file:
@IBAction func buttonClose(_ sender: Any) {

I put this after the viewDidLoad() function. Without that function connected to the Close button, when you try testing your app, you will be unable to dismiss the sheet, thus to close that window.

The menu command to open the preferences sheet now needs to be set up to drop the sheet down. In your main ViewController.swift source file, add a new function which will be called by the menu command, and any other control such as a button which you might provide the user to open this sheet:
func showPrefs(_ sender: AnyObject) {

I put this after the viewDidLoad() function. Add this function as a user-defined action by selecting the orange First Responder icon in the main View Controller, then clicking on the Attributes Inspector at the right.

In the First Responder section, click on the + tool to add a new action, and name it showPrefs: with the type of id. This forms the link with the showPrefs() function above.

Next, in Interface Builder open the main app menu and ensure there is a menu item named Preferences… If there isn’t one, add it from the Object Library at the bottom right of the window. Then Control-drag from the Preferences… command up to the orange First Responder icon at the top of the menu bar in Interface Builder, to make that menu item’s connection. A dark grey window will them appear: scroll down in that list and connect to the showPrefs: item listed there.

If you want to call showPrefs() from another control such as a button, this is the time to add that Action with the code

All that remains now to make the preferences sheet fully functional is to complete that showPrefs() function. This needs to make the prefsViewController and to present it as a sheet:
func showPrefs(_ sender: AnyObject) {
let theSB = NSStoryboard(name: "Main", bundle: nil)
let thePVC: PrefsViewController = theSB.instantiateController(withIdentifier: "prefsViewController") as! PrefsViewController

You can now build and test your app, although nothing in the new preferences sheet will work, apart from the all-important Close button.


My source for learning how to do this is Nick Smith’s Programming Swift! Mac Apps 1, published in the iBooks Store by AppSmith Books, but any mistakes are my own.