OSX application without storyboard or xib files using Swift

if you don't want to have the @NSApplicationMain attribute, do:

  1. have a file main.swift

  2. add following top-level code:

     import Cocoa
    
     let delegate = AppDelegate() //alloc main app's delegate class
     NSApplication.shared.delegate = delegate //set as app's delegate
     NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv) //start of run loop       
    
     // Old versions:
     //  NSApplicationMain(C_ARGC, C_ARGV)
     //  NSApplicationMain(Process.argc, Process.unsafeArgv);  
    

the rest should be inside your app delegate. e.g.:

import Cocoa

class AppDelegate: NSObject, NSApplicationDelegate {
    var newWindow: NSWindow?
    var controller: ViewController?
    
    func applicationDidFinishLaunching(aNotification: NSNotification) {
        newWindow = NSWindow(contentRect: NSMakeRect(10, 10, 300, 300), styleMask: .resizable, backing: .buffered, defer: false)
        
        controller = ViewController()
        let content = newWindow!.contentView! as NSView
        let view = controller!.view
        content.addSubview(view)
        
        newWindow!.makeKeyAndOrderFront(nil)
    }
}

then you have a viewController

import Cocoa

class ViewController : NSViewController {
    override func loadView() {
        let view = NSView(frame: NSMakeRect(0,0,100,100))
        view.wantsLayer = true
        view.layer?.borderWidth = 2
        view.layer?.borderColor = NSColor.red.cgColor
        self.view = view
    }
}

I'm on Swift 5, and although my app works with the code from Noskcaj's answer, I see a bunch of [Nib Loading] Failed to connect... errors from existing nib files. I fixed it by using this in my main.swift instead:

import Cocoa

autoreleasepool {
 let delegate = AppDelegate()
 // NSApplication delegate is a weak reference,
 // so we have to make sure it's not deallocated.
 withExtendedLifetime(delegate, {
     let application = NSApplication.shared
     application.delegate = delegate
     application.run()
     application.delegate = nil
 })
}

Reference: https://stackoverflow.com/a/54239088


The top level code sample above no longer works in recent versions of Xcode. Instead use this:

import Cocoa

let delegate = AppDelegate() //alloc main app's delegate class
NSApplication.shared().delegate = delegate //set as app's delegate

let ret = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)

In Swift 4 it has changed slightly yet again,

The main file must have

import Cocoa

let delegate = AppDelegate()
NSApplication.shared.delegate = delegate

NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)

The AppDelegate must be

import Cocoa


class AppDelegate: NSObject, NSApplicationDelegate {
    var newWindow: NSWindow?
    var controller: ViewController?

    func applicationDidFinishLaunching(_ aNotification: Notification) {
        newWindow = NSWindow(contentRect: NSMakeRect(10, 10, 300, 300), styleMask: .resizable, backing: .buffered, defer: false)

        controller = ViewController()
        let content = newWindow!.contentView! as NSView
        let view = controller!.view
        content.addSubview(view)

        newWindow!.makeKeyAndOrderFront(nil)
    }
}

The view controller is the same

Tags:

Macos

Cocoa

Swift