为所有 NSWindow 调用的函数

Function called for all NSWindow

当我调用函数时,它会为所有打开的 window 调用,而不仅仅是为选定的 window。

如果函数被@IBAction调用,它被应用到选择的window。否则,它适用于所有 windows。 我怎样才能只为当前选择的 window 调用函数?

预览如下:

这是最小的可重现代码:

//  AppDelegate.swift

import Cocoa

@main
class AppDelegate: NSObject, NSApplicationDelegate {

    @objc func openMyWindow()
        {
            let storyboard:NSStoryboard = NSStoryboard(name: "Main", bundle: nil)
            guard let controller:NSWindowController = storyboard.instantiateController(withIdentifier: "WindowMain") as? NSWindowController else { return }
            controller.showWindow(self)
        }
    
    @objc func test()
        {
            NotificationCenter.default.post(name: NSNotification.Name(rawValue: "TEST"), object: nil, userInfo: nil)
        }
    
    func applicationDockMenu(_ sender: NSApplication) -> NSMenu? {
        
        let dockMenu = NSMenu()
        dockMenu.addItem(withTitle: "New window", action: #selector(openMyWindow), keyEquivalent:     "")
        dockMenu.addItem(withTitle: "test", action: #selector(test), keyEquivalent:     "")
        return dockMenu
    }

    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // Insert code here to initialize your application
    }

    func applicationWillTerminate(_ aNotification: Notification) {
        // Insert code here to tear down your application
    }

    func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
        return true
    }


}
//  ViewController.swift

import Cocoa

class ViewController: NSViewController {
    
    @objc func Test(){
        
        TextView.string = "It's applied for ALL views -> it's NOT ok"
        
    }
    
    @IBAction func button(_ sender: Any) {
        
        TextView.string = "It's applied just for this view -> it's ok"
    }
    
    @IBOutlet var TextView: NSTextView!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        
        NotificationCenter.default.addObserver(self, selector: #selector(Test), name: NSNotification.Name(rawValue: "TEST"), object: nil)
  
    }

    override var representedObject: Any? {
        didSet {
        
        }
    }


}

带有对象 nil(无对象)的通知在甚至未被评估时很难区分哪个 windows 调用了 post。

换句话说,post通知时使用object:参数。

否则,多个 windows 中的所有注册观察者将对同一个通知采取行动。

那么什么对象可以用来知道是谁发送的呢? window 当然是对象本身。

您的 WindowController 也有一个 window 它属于,只需将其地址与 posted Notifications 对象进行比较,并在它们相同时执行。 或者与最前面的 windows 地址进行比较,该地址通常是 window 用户希望根据给定的命令执行操作。

如果未设置菜单项的目标,则会将操作消息发送给第一响应者。在您看来,文本视图是第一响应者,但它不处理 test 消息并将其发送给下一个响应者。视图控制器在响应链中,将接收 test 消息。 将菜单项的selector设置为view controller的action,前面window的view controller会接收到。不需要通知。

//  AppDelegate.swift

import Cocoa

@main
class AppDelegate: NSObject, NSApplicationDelegate {

    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // Insert code here to initialize your application
    }

    func applicationWillTerminate(_ aNotification: Notification) {
        // Insert code here to tear down your application
    }

    @objc func openMyWindow() {
        let storyboard:NSStoryboard = NSStoryboard(name: "Main", bundle: nil)
        guard let controller:NSWindowController = storyboard.instantiateController(withIdentifier: "WindowMain") as? NSWindowController else { return }
        controller.showWindow(self)
    }

    func applicationDockMenu(_ sender: NSApplication) -> NSMenu? {
        let dockMenu = NSMenu()
        dockMenu.addItem(withTitle: "New window", action: #selector(openMyWindow), keyEquivalent:     "")
        dockMenu.addItem(withTitle: "test", action: #selector(ViewController.test), keyEquivalent: "")
        return dockMenu
    }

}
//  ViewController.swift

import Cocoa

class ViewController: NSViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    override var representedObject: Any? {
        didSet {
        // Update the view, if already loaded.
        }
    }

    @objc func test() {
        TextView.string = "It's applied for this view -> it's now ok"
    }
    
    @IBAction func button(_ sender: Any) {
        TextView.string = "It's applied just for this view -> it's ok"
    }
    
    @IBOutlet var TextView: NSTextView!
    
}