以编程方式关闭 sheet

Closing a sheet programmatically

我有几个进程可能需要几秒钟才能完成,我想在我的主应用程序 window 中打开一个 sheet 显示一个不确定的 ProgressWheel 和一条消息说进程进展中。我希望 sheet 在进程完成后关闭。

我试图通过对 sheet 执行 segue 并在我的 prepare(for segue) 中向它发送两个字符串值来实现它——一个 waitingMessage,因此 sheet 可以显示名称正在进行的过程的状态,以及一个 waitingState... 要么是“开始”,要么是“结束”。当我的 sheet ViewController 收到“开始”状态时,它只会显示 ProgressWheel 和消息,而当它收到“结束”状态时,它会自动关闭。

这是我正在尝试的方法,但 sheet 不会关闭,即使它收到“结束”消息 – 它只是显示,整个应用程序不会继续。

import Cocoa

class WaitingViewController: NSViewController {
    @IBOutlet weak var waitingProgressWheel: NSProgressIndicator!
    @IBOutlet weak var waitingMessageLabel: NSTextField!
    
    var waitingMessage : String = ""
    var waitingState : String = ""

    
    override var representedObject: Any? {
        didSet {
            let incomming = representedObject as! (String, String)
            waitingMessage = incomming.0
            waitingState = incomming.1
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        waitingProgressWheel.startAnimation(self)
        waitingMessageLabel.stringValue = waitingMessage
        if waitingState == "ending" {
            waitingProgressWheel.stopAnimation(self)
            waitingMessageLabel.stringValue = "Done."
            dismiss(self)
        }
    }
}

这是我准备的相关部分(用于 segue)

    override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
        if segue.identifier == "waiting" {
            var waitingInfo : (String, String) = ("","")
            waitingInfo.0 = waitingSegueMessage
            waitingInfo.1 = waitingSegueState
            (segue.destinationController as! WaitingViewController).representedObject = waitingInfo
        }
    }

这是我更新的 sheet 视图控制器:

import Cocoa

class WaitingViewController: NSViewController {
    @IBOutlet weak var waitingProgressWheel: NSProgressIndicator!
    @IBOutlet weak var waitingMessageLabel: NSTextField!
    
    var processWaitingMessage : String = ""
    var processWaitingState : ViewController.waitingState = .beginning
    var isDone : Bool? {
        didSet {
            if isDone! {
                dismiss(self)
            }
        }
    }
    
    override var representedObject: Any? {
        didSet {
            let incomming = representedObject as! (String, ViewController.waitingState)
            processWaitingMessage = incomming.0
            processWaitingState = incomming.1
            if processWaitingState == .ending {
                isDone = true
            }
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        waitingProgressWheel.startAnimation(self)
        waitingMessageLabel.stringValue = processWaitingMessage
        if processWaitingState == .ending {
            waitingProgressWheel.stopAnimation(self)
            waitingMessageLabel.stringValue = "Done."
        }
    }
}

你的做法是错误的。

您必须从呈现视图控制器更新状态。要做到这一点,您需要一个参考。

ViewController中添加一个属性

weak var waitingSheet : WaitingViewController?

WaitingViewController中添加一个函数

func updateState(_ state:  ViewController.waitingState) {
    switch state {
        case .beginning: 
           waitingProgressWheel.startAnimation(self)
           waitingMessageLabel.stringValue = "Beginning"

        case .ending: 
           waitingProgressWheel.stopAnimation(self)
           waitingMessageLabel.stringValue = "Ending"

        case .isDone:
           dismiss(self)
    } 
}

viewDidLoad更新状态为beginning

override func viewDidLoad() {
    super.viewDidLoad()
    updateState(.beginning)
}

返回 ViewController 将 sheet 的引用分配给 prepareForSegue 中的 waitingSheet(不需要预定义的 representedObject

override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
    if segue.identifier == "waiting" {
        waitingSheet = segue.destinationController as? WaitingViewController
    }
}

并从 ViewController

中的任意位置更新状态
waitingSheet?.updateState(.ending)

waitingSheet?.updateState(.isDone)

弱 属性 在 sheet 被释放后将自己设置为 nil