Как заставить мою функцию, отмеченную как @objc, работать для селектора?

Я хочу добавить NSMenuItem с этим кодом:

import Cocoa

class MyTestAppClass {
    
    var closure: () -> Void
    
    init(closure: @escaping () -> Void) {
        self.closure = closure
    }
    
    @objc func invoke () {
        closure()
    }
    
}

let myTestAppClass: MyTestAppClass = MyTestAppClass(closure: { print("Hello, world!") })

class AppDelegate: NSObject, NSApplicationDelegate {

    private var window: NSWindow!

    func applicationDidFinishLaunching(_ aNotification: Notification) {
        
        buildMainMenu()
        
        buildWindow()
  
    }
    
    private func buildMainMenu() {
        
        let appMainMenu: NSMenu = NSMenu()
        
        let mainMenu: NSMenuItem = NSMenuItem()
        mainMenu.submenu = NSMenu(title: "MainMenu")
        
        let mainMenuItem0 = NSMenuItem(title: "Test", action: #selector(myTestAppClass.invoke), keyEquivalent: "t")

        mainMenu.submenu?.items = [mainMenuItem0]

        appMainMenu.items = [mainMenu]
        NSApp.mainMenu = appMainMenu

    }
    
    private func buildWindow() {
        window = NSWindow(
            contentRect: NSRect(x: 0, y: 0, width: 100.0, height: 100.0),
            styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
            backing: .buffered, defer: false)
        
        window.center()
        window.setFrameAutosaveName("Main Window")
        window.title = "No Storyboard Window"
     
        window.makeKeyAndOrderFront(window)
    }

 
}

Xcode добавляет мой элемент в меню, но он не активен, он серый и отключен. Как я могу решить проблему, Xcode даже не показывает мне ошибку. Я пытался использовать objc_setAssociatedObject, но не смог правильно использовать его для решения проблемы, я не пытаюсь добавить расширение или любую другую функцию в NSMenu для решения проблемы, я хочу иметь более общий ответ для применения к любому представлению, которому нужен селектор , например кнопки или другие вещи.

Ах, я думаю, что это основано на моем комментарии к вашему предыдущему вопросу. Похоже, что NSMenuItem не совсем использует шаблон цель/действие, поскольку вы не можете установить цель, это всегда цепочка ответчика. Вы можете сделать эти объекты частью цепочки респондентов, но это было бы странно и привередливо. Я думаю, вам лучше просто использовать обычные методы @objc для ваших представлений, делегата приложения и т. д., которые уже участвуют в цепочке респондентов.

Alexander 13.02.2023 13:50

Целевой класс должен наследоваться от NSObject, и вы должны явно указать цель пункта меню. И экземпляр MyTestAppClass должен быть в другом классе.

vadian 13.02.2023 14:08

@Alexander NSMenuItem использует шаблон цель/действие. Вы можете установить цель. Если цель nil, то она переходит в цепочку респондентов.

Willeke 13.02.2023 14:09

@Willeke, о, интересно, action доступен как свойство, просто это не один из параметров инициализатора. Странный. Не беспокойся в таком случае

Alexander 13.02.2023 14:18

Пожалуйста, не создавайте дубликаты аккаунтов, Милен stackoverflow.com/q/75348877/3141234

Alexander 16.02.2023 05:21
Руководство для начинающих по веб-разработке на React.js
Руководство для начинающих по веб-разработке на React.js
Веб-разработка - это захватывающая и постоянно меняющаяся область, которая постоянно развивается благодаря новым технологиям и тенденциям. Одним из...
Разница между Angular и React
Разница между Angular и React
React и AngularJS - это два самых популярных фреймворка для веб-разработки. Оба фреймворка имеют свои уникальные особенности и преимущества, которые...
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Веб-скрейпинг, как мы все знаем, это дисциплина, которая развивается с течением времени. Появляются все более сложные средства борьбы с ботами, а...
Калькулятор CGPA 12 для семестра
Калькулятор CGPA 12 для семестра
Чтобы запустить этот код и рассчитать CGPA, необходимо сохранить код как HTML-файл, а затем открыть его в веб-браузере. Для этого выполните следующие...
ONLBest Online HTML CSS JAVASCRIPT Training In INDIA 2023
ONLBest Online HTML CSS JAVASCRIPT Training In INDIA 2023
О тренинге HTML JavaScript :HTML (язык гипертекстовой разметки) и CSS (каскадные таблицы стилей) - две основные технологии для создания веб-страниц....
Как собрать/развернуть часть вашего приложения Angular
Как собрать/развернуть часть вашего приложения Angular
Вам когда-нибудь требовалось собрать/развернуть только часть вашего приложения Angular или, возможно, скрыть некоторые маршруты в определенных средах?
0
5
87
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В вашей демонстрации есть пара ошибок:

  1. Нет "главного"
  2. Необходимо установить цель для элемента меню

Следующий исходный код должен работать в Xcode, если вы создаете быстрый проект и удаляете предварительно предоставленный код AppDelegate, копируете/вставляете следующий код на его место и изменяете имя «AppDelegate.swift» на «main.swift»:

import Cocoa

class MyTestAppClass {
    var closure: () -> Void
    
    init(closure: @escaping () -> Void) {
        self.closure = closure
    }
    
    @objc func invoke() {
        closure()
    }
}

let myTestAppClass: MyTestAppClass = MyTestAppClass(closure: { print("Hello, world!") })

class AppDelegate: NSObject, NSApplicationDelegate {
    var window: NSWindow!

    func applicationDidFinishLaunching(_ aNotification: Notification) {
        buildMainMenu()
        buildWindow()
    }
    
   func buildMainMenu() {
        let appMainMenu: NSMenu = NSMenu()
        let mainMenu: NSMenuItem = NSMenuItem()
        mainMenu.submenu = NSMenu(title: "MainMenu")
        let mainMenuItem0 = NSMenuItem(title: "Test", action: #selector(myTestAppClass.invoke), keyEquivalent: "t")
        mainMenuItem0.target = myTestAppClass
        mainMenu.submenu?.items = [mainMenuItem0]
        appMainMenu.items = [mainMenu]
        NSApp.mainMenu = appMainMenu
    }
    
    func buildWindow() {
        window = NSWindow(contentRect: NSRect(x: 0, y: 0, width: 100.0, height: 100.0), styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView], backing: .buffered, defer: false)
        window.center()
        window.setFrameAutosaveName("Main Window")
        window.title = "No Storyboard Window"
        window.makeKeyAndOrderFront(window)
    }
}

let appDelegate = AppDelegate()

// **** Main **** //
let application = NSApplication.shared
application.delegate = appDelegate
application.run()


Я попробовал ваш данный код и посмотрел на мой данный код, о котором идет речь, единственная недостающая часть была mainMenuItem0.target = myTestAppClass, почему мне нужно добавить (_ sender:AnyObject) для вызова функции, поскольку коды работают и без нее, что касается основного файла, я предполагаю, что любой человек, который может ответить в этом вопросе можно разобраться без упоминания о нем в вопросе. Кстати, спасибо за вашу помощь, мне просто нужно знать, зачем мне нужен (_ sender:AnyObject) в моем коде?

user21186802 13.02.2023 21:30

Они продолжают менять быстрый язык. Раньше мне приходилось его использовать, но, похоже, вы правы, что сейчас он нам не нужен. Я пересмотрю свой ответ. Спасибо за продолжение.

apodidae 13.02.2023 21:50

Спасибо, я не могу голосовать, потому что я новичок, вы хорошо поработали!

user21186802 13.02.2023 23:16

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