It's a long story, but to cut it short; my first OSX app was written (on Yosemite) in Swift using a storyboard until I found out my (finished) app will not run on Mavericks. I need to run on Mavericks, so I have replaced the storyboard with NIBs.
My problem is with the segues; I was using 'sheet type' segues to show other view controllers in a sheet over the main view controller. A call to the presentViewControllerAsSheet method of NSViewController is a good replacement as it looks the same, but this API was introduced in Yosemite - so I need to work out how to do this for Mavericks.
In the action for a button on the main view, I've tried using beginSheet like this:
secondViewController = SecondViewController(nibName: "SecondViewController", bundle: nil)
self.view.window?.beginSheet(secondViewController!view.window!, completionHandler: nil)
But the second view controller's window is null at runtime. I've tried adding the new view controller as a subview to the application window but this is an unrecognised selector:
NSApplication.sharedApplication().windows[0].addSubView(secondViewController!.view)
I've search high and low for a description of how to show a sheet and all I can find is: Can a view controller own a sheet? but I'm sorry to admit I don't understand the answer. Can anybody help me with some working code? I'm beginning to worry that I'm trying to do something unusual but it looks OK on Yosemite, so how did people do this before Yosemite was released?
EDIT I still haven't got to the solution, so I have put together a small app which shows the problems I'm having.
In AppDelegate.swift:
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var window: NSWindow!
var mainViewController: FirstView!
func applicationDidFinishLaunching(aNotification: NSNotification) {
mainViewController = FirstView(nibName:"FirstView", bundle: nil)
window.contentView = mainViewController.view
mainViewController.view.frame = (window.contentView as! NSView).bounds
}
}
In FirstView.swift (associated NIB has a 'open sheet' button)
class FirstView: NSViewController {
var secondView: SecondView?
var secondWindow: SecondWinCon?
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func pressButton(sender: AnyObject) {
secondView = SecondView(nibName: "SecondView", bundle: nil)!
// method 1 - this is the behaviour I want (but it only works on OSX 10.10)
// presentViewControllerAsSheet(secondView!)
// method 2 - this just creates a floating window
// self.view.addSubview(secondView!.view)
// self.view.window?.beginSheet(secondView!.view.window!, completionHandler: nil)
// method 3 - this also creates a floating window
secondWindow = SecondWinCon(windowNibName: "SecondWinCon")
self.view.window?.beginSheet(secondWindow!.window!, completionHandler: nil)
}
}
In SecondView.swift (associated NIB has a 'close' button)
class SecondView: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func dismissPressed(sender: AnyObject) {
if (presentingViewController != nil) {
presentingViewController?.dismissViewController(self)
} else {
self.view.window?.sheetParent?.endSheet(self.view.window!)
}
}
}
In SecondWinCon.swift (Associated NIB is empty)
class SecondWinCon: NSWindowController {
var secondView: SecondView?
override func windowDidLoad() {
super.windowDidLoad()
secondView = SecondView(nibName: "SecondView", bundle: nil)!
self.window?.contentView.addSubview(secondView!.view)
}
}
If method 1 is uncommented, you will see the behaviour I'm trying to emulate (remember it only works on OS X 10.10). Method 2 or 3 displays the second view, but not as a sheet.
If you get here looking for a solution, I was nearly there with method 3. The important step I had missed was to turn off "Visible At Launch" in the NSWindowController's NIB (it's an attribute of the NSWindow). In my sample code, this was in SecondWinCon.nib.