Creating an AppKit App Without the Storyboard
Creating an AppKit App Without the Storyboard
There are many reasons to want to build an AppKit app without a storyboard. Usually the largest advantage is that in a team environment, storyboards can be a nightmare for version control. It’s much easier to resolve conflicts in code than in a .storyboard XML file. Of course you can use SwiftUI, but there are also reasons for wanting to avoid using SwiftUI as your base as of 2023.
Prerequisites
We’re going to assume you’re running on Xcode 14+.
Create your project
Create your Xcode project in AppKit, selecting Storyboard initially – don’t worry, we will remove in a moment.
Delete the Main.storyboard
Make sure to move it to the trash.
Update your target settings
In your main target, delete the AppKit Main Storyboard File Base Name
Create your main.swift file
At the root of the project, create a main.swift
file.
import Cocoa
let appDelegate = AppDelegate()
NSApplication.shared.delegate = appDelegate
_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
Remove the @main notation on the AppDelegate
Remove the @main
attribute before your AppDelegate:
@main
class AppDelegate: NSObject, NSApplicationDelegate {
// rest of code
}
Setup your first ViewController from the App Delegate
class MyCustomViewController: NSViewController {
override func loadView() {
self.view = NSView()
self.view.frame = NSRect(x: 0, y: 0, width: 200, height: 200)
self.view.wantsLayer = true
self.view.layer?.backgroundColor = NSColor.red.cgColor
}
}
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Create a window
window = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
styleMask: [.titled, .closable, .resizable, .fullSizeContentView],
backing: .buffered, defer: false)
window.center()
window.title = "No Storyboards Here"
// Create an instance of your view controller
let myViewController = MyCustomViewController()
// Set the window's content view to the view controller's view
window.contentView = myViewController.view
window.makeKeyAndOrderFront(nil)
}