osx: 在 NSWindowController 和 NSViewController 之间进行委托

osx: Delegating between a NSWindowController and a NSViewController

这里简化了我的问题。我有一个工具栏,在 Window 中有一个按钮,在视图中有一个标签。单击按钮后,我想 label.stringValue 从 "ON" 变为 "OFF"

这是 Window控制器:

protocol ViewControllerDelegate {
    func switchOnOff()
}

class WindowController: NSWindowController {
    var viewDelegate: ViewControllerDelegate?
    @IBAction func pressedButton(_ sender: Any) {
        var vc = storyboard?.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: "ViewController")) as? ViewController
        vc?.switchOnOff()
    }    
    override func windowDidLoad() {
        super.windowDidLoad()
    }
}

这是视图控制器:

class ViewController: NSViewController {
    @IBOutlet weak var onOffLabel: NSTextField!
    override func viewDidLoad() {
        super.viewDidLoad()
        let vc = WindowController()
        vc.viewDelegate = self    }

    override var representedObject: Any? {
        didSet {
        }
    }
}

extension ViewController: ViewControllerDelegate {
func switchOnOff() {
    if (onOffLabel.stringValue == "OFF" ) {
        onOffLabel.stringValue = "ON"
    } else {
        onOffLabel.stringValue = "OFF"
    }       
}

}

这是故事板:

当我点击按钮时出现这个错误:

extension ViewController: ViewControllerDelegate {
    func switchOnOff() {
        if (onOffLabel.stringValue == "OFF" ) { // Thread 1: Fatal error: Unexpectedly found nil while unwrapping 
        an Optional value
            onOffLabel.stringValue = "ON"
        } else {
            onOffLabel.stringValue = "OFF"
        }
    }
}

希望这个回答还不算太晚。

委托的工作方式是您告诉发件人要发送给谁。您遇到的问题是您创建了一个新的 WindowController 实例并注册为它的接收者。问题是 WindowController 的新实例不是发送按钮点击操作的实例。

要使其正常工作,您必须将 ViewController 注册到 WindowController 的唯一实例。

而不是做

let vc = WindowController()
vc.viewDelegate = self

您需要找到实际的 Window 控制器实例并注册到该实例。将上面的代码改成:

(self.view.window?.windowController as! WindowController).delegate = self

一切都应该完美无缺。