为所有 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!
}
当我调用函数时,它会为所有打开的 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!
}