Как представить ViewControllerAsSheet на OSX Маверикс?

Это длинная история, но, чтобы сократить ее; мое первое OSX-приложение было написано (на Yosemite) в Swift с использованием раскадровки, пока я не узнал, что мое (законченное) приложение не будет работать на Mavericks. Мне нужно работать на Mavericks, поэтому я заменил раскадровку на NIB.

Моя проблема с segues; Я использовал сегменты типа листа, чтобы показать другие контроллеры представления на листе поверх контроллера основного вида. Вызов метода presentViewControllerAsSheet в NSViewController является хорошей заменой, поскольку он выглядит так же, но этот API был представлен в Yosemite - поэтому мне нужно разобраться, как это сделать для Mavericks.

В действии для кнопки на главном экране я попытался использовать begin Sheet следующим образом:

secondViewController = SecondViewController(nibName: "SecondViewController", bundle: nil)
self.view.window?.beginSheet(secondViewController!view.window!, completionHandler: nil)

Но второе окно контроллера представления является нулевым во время выполнения. Я попытался добавить новый контроллер представления как подпредставление к окну приложения, но это нераспознанный селектор:

NSApplication.sharedApplication().windows[0].addSubView(secondViewController!.view)

Я искал все выше и ниже описания того, как показать лист, и все, что я могу найти, это: Может ли контроллер представления владеть листом? но мне жаль признаться, что я не понимаю ответ. Кто-нибудь может мне помочь с некоторым рабочим кодом? Я начинаю беспокоиться, что я пытаюсь сделать что-то необычное, но на Yosemite все выглядит нормально, так как же люди делали это до того, как Yosemite был выпущен?

РЕДАКТИРОВАТЬ Я до сих пор не нашел решения, поэтому я собрал небольшое приложение, которое показывает мои проблемы.

В 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
    }
}

В FirstView.swift (связанный NIB имеет кнопку "открыть лист")

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)   
    }    
}

В SecondView.swift (связанный NIB имеет кнопку "Закрыть")

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!)
        }
    }
}

В SecondWinCon.swift (связанный NIB пуст)

class SecondWinCon: NSWindowController {
    var secondView: SecondView?
    override func windowDidLoad() {
        super.windowDidLoad()   
        secondView = SecondView(nibName: "SecondView", bundle: nil)!
        self.window?.contentView.addSubview(secondView!.view)
    }   
}

Если метод 1 не закомментирован, вы увидите поведение, которое я пытаюсь эмулировать (помните, что оно работает только в OS X 10.10). Метод 2 или 3 отображает второе представление, но не в виде листа.

2 ответа

Решение

Если вы попали сюда в поисках решения, я почти подошел к методу 3. Важным шагом, который я пропустил, было отключение "Visible At Launch" в NIB NSWindowController (это атрибут NSWindow). В моем примере кода это было в SecondWinCon.nib.

У меня та же проблема, и я обнаружил, что, возможно, это не проблема, связанная с просмотром жизненного цикла. Когда я вызываю presentViewControllerAsSheet в viewDidLoad, лист не будет показан, и вы получите это в консоли:

Не удалось установить (contentViewController) определяемое пользователем проверяемое свойство для (NSWindow): presentViewController:animator:: View 'представление не находится в иерархии окна / представления.

Если вы активируете это в viewWillAppear или viewDidAppear, это совершенно не проблема.

ОБНОВИТЬ

Хорошо, давайте проясним это.

Для этой первоначальной раскадровки NSWindowController связан с контроллером представления, представьте его как корневой контроллер представления (RootVC). Создайте другой желаемый контроллер представления в виде листа в раскадровке (SheetVC). в viewWillAppear или viewDidAppear RootVC, [self presentViewControllerAsSheet: SheetVC]

Лист покажет, дополнительный код не требуется.

Другие вопросы по тегам