Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AppDelegate for Cocoa app using Storyboards in Xcode 6

Tags:

cocoa

xcode6

I have an existing OS X app, and after converting to Storyboards as the main interface, my app delegate is no longer being used. Before, the MainMenu.xib had an "App Delegate" object, and I could set its class to my app delegate. However, the Storyboard contains no such object.

How do I get my AppDelegate back and keep storyboards? I feel like I'm missing something obvious.

like image 586
Adam Fox Avatar asked Jun 12 '14 20:06

Adam Fox


1 Answers

If you don't specify it to be a Document-Based Application, Xcode will create an AppDelegate.swift class and connect it up in the Application Scene for you.

As of right now (Xcode Beta-2), new Document-Based apps don't come with a stub AppDelegate.swift file. Instead, there's ViewController.swift and Document.swift. Worse, the Document.swift file incorrectly instantiates the same Main.storyboard for documents.

Here's one way I got it to work:

  1. Create an AppDelegate class (e.g.: an NSObject that adopts the NSApplicationDelegate protocol)

  2. Drag an Object object from the Object library, into the Application Scene of Main.storyboard and set it to the AppDelegate class.

  3. Control-drag from the Application object in the Application Scene to the AppDelegate object, and connect up its delegate.

  4. Remove everything else from the Main.storyboard and create a new Document.storyboard for the Document window. Change the Document.swift file to instantiate that Storyboard instead of Main.

  5. If you want to have a main application window and/or a preferences window in addition to your document windows, create an Application.storyboard and/or Preferences.storyboard for those windows, and use the AppDelegate class to instantiate them. This way, the AppDelegate can customize the main window appearance and do other handy things, including receiving IBActions sent from any window in the app.

Here's a working example of an AppDelegate.swift file for a Document-Based app that also has a separate, single main Application window, and a non-modal Preference window:

//  AppDelegate.swift

import Cocoa

class AppDelegate: NSObject, NSApplicationDelegate {

    //init() {   
    //    super.init() 
    // remove this if you don't use it
    //}

    var application: NSApplication? = nil
    func applicationDidFinishLaunching(notification: NSNotification) {
        application = notification.object as? NSApplication

        let path = NSBundle.mainBundle().pathForResource("Defaults", ofType: "plist")
        let defaults = NSDictionary(contentsOfFile:path)
        NSUserDefaults.standardUserDefaults().registerDefaults(defaults)
        NSUserDefaultsController.sharedUserDefaultsController().initialValues = defaults
        NSUserDefaultsController.sharedUserDefaultsController().appliesImmediately = true

    }

    func applicationDidBecomeActive(notification: NSNotification) {
        if application?.orderedDocuments?.count < 1 { showApplication(self) }
    }

    //func applicationWillFinishLaunching(notification: NSNotification) {
        // remove this if you don't use it
     //}

    func applicationWillTerminate(notification: NSNotification) {
       NSUserDefaults.standardUserDefaults().synchronize()

    }

    func applicationShouldOpenUntitledFile(app: NSApplication) -> Bool { return false }

    func applicationShouldTerminateAfterLastWindowClosed(app: NSApplication) -> Bool { return false }

    var applicationController: NSWindowController?
    @IBAction func showApplication(sender : AnyObject) {
        if !applicationController {

            let storyboard = NSStoryboard(name: "Application", bundle: nil)
            applicationController = storyboard.instantiateInitialController() as? NSWindowController
            if let window = applicationController?.window {
                window.titlebarAppearsTransparent = true
                window.titleVisibility = NSWindowTitleVisibility.Hidden
                window.styleMask |= NSFullSizeContentViewWindowMask
            }


        }
        if applicationController { applicationController!.showWindow(sender) }
    }

    var preferencesController: NSWindowController?
    @IBAction func showPreferences(sender : AnyObject) {
        if !preferencesController {
            let storyboard = NSStoryboard(name: "Preferences", bundle: nil)
            preferencesController = storyboard.instantiateInitialController() as? NSWindowController
        }
        if preferencesController { preferencesController!.showWindow(sender) }
    }

}

like image 73
ElmerCat Avatar answered Dec 01 '22 16:12

ElmerCat