33

Unfortunately, I haven't found anything useful on the Internet - I wanted to know, what code I actually have to type for initializing an application without using storyboard or XIB files in Swift. I know I have to have a .swift file called main. But I don't know what to write in there (like do I need autoreleasepool or something like that?). For example, what would I do for initializing an NSMenu and how would I add a NSViewController to the active window (iOS's similar .rootViewController doesn't help). Thanks for any help ;)

Edit: I actually don't want to use @NSApplicationMain in front of the AppDelegate. I'd rather know what exactly happens there and then do it myself.

1
  • I'm not sure why would you ever want to avoid @NSApplicationMain, but this question sure does have good educational value behind the scenes! Commented Apr 12, 2019 at 23:05

4 Answers 4

35

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
    }
}
Sign up to request clarification or add additional context in comments.

9 Comments

How would I then display several view controllers on the window? Or should I use different windows hiding and showing when they are needed? Or is there even another effort to do this?
I agree with leonardo that for more complex stuff you should use xibs -- I don't quite often but if you're stuck on this level, I would do so
sorry this isn't 'write all my code for me' - your question was 100% answered and you can ask either different specific questions or (better maybe) try some tutorials
It's func applicationDidFinishLaunching(_ notification: Notification) in Swift 3.1. Pure copy and paste led to some confusion on my part.
When I try this with Xcode 9 the app terminates complaining that it cannot find a xib file. Where do I tell NSApplication not to use a xib file?
|
18

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)

3 Comments

No longer works in Swift 4. I spent hours and still no luck programmatically create a window with pure swift. Apple makes is so hard to do it (\read no official getting started guide without storyboard )
@Kun Have you found a solution for this?
@BohdanSavych I did, shared is now a computed property, so drop the parentheses after that.
10

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

1 Comment

For anyone like me looking to make window showing title frame window = NSWindow(contentRect: winSize, styleMask: [.miniaturizable, .closable, .resizable, .titled], backing: .buffered, defer: false)
1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.