NSApplicationDelegate not working without Storyboard
You need to do a few things here
- Delete
NSMainStoryboardFile
key/value from the plist - Create a
NSApplication
subclass and assign it to thePrincipal Class (NSPrincipalClass)
key.
The name must be fully qualified with your module name.
- Manually instantiate your delegate in your NSApplication subclass and assign it to the
delegate
property.
Make sure you keep a strong reference to your delegate object. Ive just used a let
here.
class GrookApplication: NSApplication {
let strongDelegate = AppDelegate()
override init() {
super.init()
self.delegate = strongDelegate
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
e.g a simple delegate.
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
override init() {
super.init()
print("wassup")
//conceptual proof of life init override
//wait until applicationDidFinishLaunching , specially for UI
}
var window: NSWindow!
func applicationDidFinishLaunching(_ aNotification: Notification) {
print("yo! I'm alive")
window = NSWindow(contentRect: NSRect(x: 0, y: 0, width: 200, height: 200), styleMask: .titled, backing: .buffered, defer: false)
window.makeKeyAndOrderFront(nil)
}
}
EDIT 2018 Verified High Sierra
Do NOT try and do window or view controller initialisation inside init
this leads to double app initialisation issues and crashing. The app has not finished launching at this stage. Wait until applicationDidFinishLaunching
to fire any significant operations.
macOS statusBarApp without Storyboard create and close settingsWindow causing EXC_BAD_ACCESS
NSWindow
is released when it is closed. Before ARC this was a usefull feature. It can be switched off by setting the isReleasedWhenClosed
property to false
. But then the window stays in memory when it is closed because the settingsWindow
property is holding on to it. Implement delegate method windowWillClose
and set settingsWindow
to nil
so window is released.
class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
var settingsWindow: NSWindow!
// other methods
@objc func createWindow() {
settingsWindow = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 750, height: 500),
styleMask: [.miniaturizable, .closable, .resizable, .titled],
backing: .buffered, defer: false)
settingsWindow.isReleasedWhenClosed = false
settingsWindow.delegate = self
settingsWindow.center()
settingsWindow.title = "No Storyboard Window"
settingsWindow?.contentViewController = ViewController()
settingsWindow.makeKeyAndOrderFront(nil)
}
func windowWillClose(_ notification: Notification) {
settingsWindow = nil
}
}
OSX application without storyboard or xib files using Swift
if you don't want to have the @NSApplicationMain attribute, do:
have a file main.swift
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
}
}
how to prevent storyboard from opening a window
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
var defaultWindow:NSWindow!
func applicationDidFinishLaunching(aNotification: NSNotification) {
defaultWindow = NSApplication.sharedApplication().windows.first as? NSWindow
defaultWindow.close()
}
func applicationWillTerminate(aNotification: NSNotification) {
// Insert code here to tear down your application
}
@IBAction func menuClick(sender: AnyObject) {
defaultWindow.makeKeyAndOrderFront(nil)
}
}
update: Xcode 7.1.1 • Swift 2.1
NSApplication.sharedApplication().windows.first?.close()
Crash when closing window in a MacOS application?
The problem is the window is automatically released (and thus deallocated) upon closure. This, combined with the automatic reference counting, presumably creates a sort of double free error. To solve this problem without disabling ARC or disabling releaseWhenClosed
, Window
is made a global or instance variable. Doing so will prevent ARC from releasing the window after already having been released by being closed.
NSWindow *Window;
// ...
- (void)applicationDidFinishLaunching:(NSNotification *)Notification {
Window = [[NSWindow alloc] initWithContentRect:(NSRect){.size = {800, 512}} styleMask:NSWindowStyleMaskTitled|NSWindowStyleMaskClosable|NSWindowStyleMaskMiniaturizable|NSWindowStyleMaskResizable backing:NSBackingStoreBuffered defer:YES];
[Window center];
[Window makeKeyAndOrderFront:Window];
// Insert code here to initialize your application
}
applicationDidFinishLaunching not called, using storyboards and swift3
Even if your app is running as an agent your storyboard is supposed to have this structure:
If not, drag a blue cube (object) into the application scene, set the class of the object to AppDelegate
and control-drag from Application
to App Delegate
and select delegate
.
If you even have no Application Scene, create a new project with storyboard enabled, delete your current Main.storyboard file and drag the Main.storyboard of the new created project into your current project.
macOS: How to create and launch a NSViewController without using Xib/Storyboard
The size of the view is (0, 0) and the window is resized to the fit the view. Use a bigger view:
override func loadView() {
view = NSView(frame: NSMakeRect(0, 0, 500, 500))
}
Related Topics
When and How to Use @Noreturn Attribute in Swift
Drag Rotate a Node Around a Fixed Point
Difference Between String Interpolation and String Initializer in Swift
Swift 2 Protocol Extension Not Calling Overridden Method Correctly
Alamofire: Send JSON with Array of Dictionaries
In Swift, What Does It Mean for Protocol to Inherit from Class Keyword
Draw a Hole in a Rectangle with Spritekit
Set the Size and Position of All Windows on the Screen in Swift
App Delegate Accessing Environment Object
"Unrecognized Selector Sent to Instance" in Swift
Get the Accurate Duration of a Video
Using Stringbyreplacingcharactersinrange in Swift
How to Write Inline Assembly in Swift
Swiftui Call Function on Variable Change
Difference Between Associated and Raw Values in Swift Enumerations
How to Print a String from Plist Without "Optional"