Michael Knudsen
Michael Knudsen

Reputation: 629

Connect to ViewController from AppDelegate (Swift)

I have created a new OS X Cocoa Application using the standard Xcode Swift template (using StoryBoards).

I have implemented an IBAction in AppDelegate.swift to handle when the users selects "Open..." from the "File" menu. If the chosen file is a valid image file, I create an NSImage which I then want to display in the view of ViewController.

    @IBAction func openFile(sender: NSMenuItem) {
    var openPanel = NSOpenPanel()
    openPanel.beginWithCompletionHandler { (result :Int) -> Void in
        if result == NSFileHandlingPanelOKButton {
            if let imageURL = openPanel.URL {
                let image = NSImage(contentsOfURL: imageURL)
                // PRESENT image IN THE VIEW CONTROLLER
            }
        }
    }

However, I don't see any way to connect to ViewController from AppDelegate. I have only managed to find suggestions that I should look at self.window! in AppDelegate, but there is no such thing as a window in AppDelegate.

Thanks, Michael Knudsen

Upvotes: 9

Views: 11595

Answers (5)

regina_fallangi
regina_fallangi

Reputation: 2198

In Swift 5 and accessing new windows array:

@IBAction func menuAction(sender: AnyObject) {
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let controller = storyboard.instantiateInitialViewController()
    // The windows in the array are ordered from back to front by window level;
    // thus, the last window in the array is on top of all other app windows.
    // On app launch, UIApplication.shared.windows.count == 1 anyway.
    if let window = UIApplication.shared.windows.last {
        window.rootViewController = controller
    }
}

Upvotes: 0

John Pavley
John Pavley

Reputation: 5406

You can access the mainWinow property and the contentViewController property to create a reference to your custom ViewController class. This is similar to the iOS rootViewController property.

let rootViewController = NSApplication.shared().mainWindow?.windowController?.contentViewController as! ViewController

Now you can use this reference to access IBOutlets on your main storyboard from your AppDelegate.

rootViewController.myTextView.textStorage?.mutableString.setString("Cats and dogs.")

This is good for a simple app with one Window with one ViewController.

Upvotes: 4

roborom
roborom

Reputation: 1

If you control-drag from the menu to the first responder (red cube above menu) and picked an existing action, then you can "responder chain" to your view controller. In my case I attached Open to openFile and then in my view controller I added the following

override var acceptsFirstResponder: Bool {
    return true
}

func openFile(sender: NSMenuItem) {
    print("In view controller")
}

and it worked without any changes in AppDelegate. Most of the menus are already hooked up to first responder so just add the matching function name in your view controller.

See this comment and this document on Event Handling Basics for more info.

Upvotes: 0

Subcreation
Subcreation

Reputation: 1353

I was stuck trying to do this same thing recently and managed to get the event I needed to update my view by creating the @IBAction in my ViewController and control dragging to my Application's First Responder (above the menu in my storyboard view).

Here's the question that got me out of the woods: Application Menu Items Xcode

And thanks to Bluedome for the suggestion to connect it to First Responder's action.

Upvotes: 1

bluedome
bluedome

Reputation: 2459

It seems that AppDelegate can connect to objects only within Application Scene in a storyboard. If you want to get a ViewController, instantiate it from a storyboard.

sample:

@IBAction func menuAction(sender: AnyObject) {
    if let storyboard = NSStoryboard(name: "Main", bundle: nil) {
        let controller = storyboard.instantiateControllerWithIdentifier("VC1") as NSViewController

        if let window = NSApplication.sharedApplication().mainWindow {
            window.contentViewController = controller // just swap
        }
    }
}

Upvotes: 18

Related Questions