Swift without Interface Builder for MacOS

GUI built using Swift without Interface Builder
GUI built using Swift without Interface Builder

Many tutorials on writing apps try to do almost everything graphically and use very little code.  This is great for demonstrating how easy it is to quickly write an app but can leave one without real understanding.  When the graphical approach does not quite do what you want it can leave you struggling to figure out how to proceed.  Recently I was porting an app to Swift 4 and Xcode 9 and trying to find settings and connections.  Perhaps more Swift code and less graphical settings might lead to less fragmented code which could be easier to understand in the long run.  At a minimum it might lead to a better understanding and provides a chance to actually write a substantial amount of Swift code.

Some people have taken the approach of avoiding xib files.  Jeff Johnson advocates avoiding nibs but is using Objective C and does not provide a code example.  John Stricker of Raizlabs mentions difficulties in merging conflicts in source control and debugging problems in Interface Builder.  He provides example code for an iOS app.

Example Swift code

NSStackView is used because it provides a way to create a hierarchical structure for the graphical user interface.  Later exploration will look at whether this helps simplify layout constraints.  The NSStackView will contain two buttons which provide a visual feedback.  These will all be contained in a window.  More complicated graphical interfaces will have more elements but should just repeat the patterns.

Start by creating a new Xcode project.  This is going to be a Cocoa App.  In AppDelegate.swift the initial code is

@IBOutlet weak var window: NSWindow!

func applicationDidFinishLaunching(_ aNotification: Notification) {
    // Insert code here to initialize your application
}

func applicationWillTerminate(_ aNotification: Notification) {
    // Insert code here to tear down your application
}

The first step is to change the @IBOutlet since we are not using Interface Builder.  The new code is simply declaring a window.

var window: NSWindow!

Now we are going to add code to the function applicationDidFinishLaunching(). The first step is to create a view controller.

func applicationDidFinishLaunching(_ aNotification: Notification) {
    let mainViewController = NSViewController()
}

The next step is to create an array of buttons that contains two buttons.

var buttons = [NSButton]()
let addButton = NSButton()
addButton.title = "Add"
buttons += [addButton]
let removeButton = NSButton()
removeButton.title = "Remove"
buttons += [removeButton]

The NSStackView is now created with the two buttons.

let stackView = NSStackView(views: buttons)

The last step is to add the NSStackView to the view controller and attach the view controller to the window.

mainViewController.view = stackView
self.window.contentView?.addSubview(mainViewController.view)

Putting this all together the code in the AppDelegate class should be

var window: NSWindow!

func applicationDidFinishLaunching(_ aNotification: Notification) {
    let mainViewController = NSViewController()

    var buttons = [NSButton]()
    let addButton = NSButton()
    addButton.title = "Add"
    buttons += [addButton]
    let removeButton = NSButton()
    removeButton.title = "Remove"
    buttons += [removeButton]

    let stackView = NSStackView(views: buttons)
    mainViewController.view = stackView
    self.window.contentView?.addSubview(mainViewController.view)
}

func applicationWillTerminate(_ aNotification: Notification) {
    // Insert code here to tear down your application
}

Now we can build the app and run it. The result should be similar to the image above.  Additional elements would be added in a similar way by nesting NSStackViews.  Layout constraints are omitted so the buttons appear in the lower left hand corner.

This tutorial shows building a simple graphical interface just using Swift code without Interface Builder. There are times when Interface Builder might be a better approach but it is good to know how to just use code to build a graphical user interface.

Categories