Programmatic mac app


My notes on programatic macOS app

  • This code creates a pure programatic setup w/o storyboard
  • (Uncheck use storyboard when you create the project) 🚫
  • Since xCode 11.2 you have to tick use XIB ✅
  • Since xCode 13.x we have to add info.plist manually to the root of the project. Then add it in build settings infoplist field. and remove from build phase.

The code:

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
   @IBOutlet weak var window: NSWindow!
   /**
    * Creates the view
    */
   lazy var view: NSView = createView()
   func applicationDidFinishLaunching(_ aNotification: Notification) {
      _ = view
   }
}
extension AppDelegate {
   func createView() -> NSView {
      let contentRect = window.contentRect(forFrameRect: window.frame)/*size of win sans titlebar*/
      let view: View = .init(frame: contentRect)
      window.contentView = view
      view.layer?.backgroundColor = NSColor.white.cgColor
      return view
   }
}
open class View: NSView {
   override open var isFlipped: Bool { return true }/*TopLeft orientation*/
   override public init(frame: CGRect) {
      super.init(frame: frame)
      Swift.print("hello world")
      self.wantsLayer = true/*if true then view is layer backed*/
   }
   /**
    * Boilerplate
    */
   public required init?(coder decoder: NSCoder) {
      fatalError("init(coder:) has not been implemented")
   }
}

Gotchas

Sometimes you have to set the signing certificate to run locally

Headless app:

// the bellow code must be added to AppDelegate.swift
import Cocoa

class AppDelegate: NSObject, NSApplicationDelegate {
   func applicationDidFinishLaunching(_ aNotification: Notification) {
      // Insert code here to initialize your application
      Swift.print("hello world")
   }
   func applicationWillTerminate(_ aNotification: Notification) {
      // Insert code here to tear down your application
   }
}
// the bellow code must be added to main.swift
import Cocoa

private let app = NSApplication.shared
private let delegate = AppDelegate()
app.delegate = delegate
app.run()