So, your code did not run, but you had this crash report ? Right ?
2019-12-08 22:33:32.117410+0100 Edgar[2669:436738] [Nib Loading] Failed to connect (object) outlet from (Edgar.AppDelegate) to (NSMenuItem): missing setter or instance variable
That's not a crash, but some nemuItem won't be loaded.
You may have missed a connection somewhere.
Let's check on a systematic way (please answer precisely to each question):
- You created Word class menu in IB. Right ?
If not, where did you create ?
It yes (which I assume):
- You created a menu in the menu bar (will be named "Word class" later) by inserting an NSMenuItem in the menu bar. Right ?
- in this menu, you inserted a menu (dragging menu object on the newly created MenuItem. Right ?
- you gave this Menu the title Word class in IB (attributes inspector of the Menu, not the menu item). Right ?
Note take care that the spelling, incl lower and upper case be exactly what you put in code
- You inserted 2 sub menu items in this menu and named them "Noun group" and "Pronoun". They appear with a right pointing arrow. Right ?
- You may have removed the other 3 items without arrow.
- You click on Noun group ; you see a submenu item, named item1. You select and rename "Subject"
- You drag a menu item below Subject and name it "Object". Right ?
- You added submenus to Pronoun in the same way.
Did you declare IBOutlets for some of those elements ? Such as Subject or Object ?
How do they show in code: please copy the IBOutlet declarations.
Have you defined a xib for some of the menus ? If so, detail which
Did you connect some of this item to an IBAction ?
If yes, which action ?
Please show the code for the action
You get a print:
actionForItem Subject NSControlStateValue(rawValue: 1)
So, you have correctly connected the Subject menuItem to its IBAction
So probably, myItemSubmenu is nil.
Please add other prints:
@IBAction func actionForItem(_ sender: NSMenuItem) {
sender.state = sender.state == .on ? .off : .on
print("actionForItem", sender.title, sender.state)
textResult.stringValue = "Clicked on = " + sender.title // For test purpose
// The following is hardcoded for test purpose
let mainMenu = NSApplication.shared.mainMenu!
let firstMenu = mainMenu.item(withTitle: "Word class")?.menu
print("firstMenu", firstMenu)
let myItemSubmenu = firstMenu?.item(withTitle: "Noun group")?.submenu // will be nil if there is not submenu (hierarchical)
print("myItemSubmenu", myItemSubmenu)
myItemSubmenu?.item(withTitle: "Subject")?.isEnabled = true
print("myItemSubmenu?.item ", myItemSubmenu?.item(withTitle: "Subject"))
}
THE PROBLEM: it is the way you access to menu elements.
Instead of:
let mainMenu = NSApplication.shared.mainMenu!
let firstMenu = mainMenu.item(withTitle: "Word class")?.menu
let myItemSubmenu = firstMenu?.item(withTitle: "Noun group")?.submenu // will be nil if there is not submenu (hierarchical)
myItemSubmenu?.item(withTitle: "Subject")?.isEnabled = true
you should write (I have added a 2 at the end of names to make it clear about the changes):
let mainMenu = NSApplication.shared.mainMenu!
let firstMenu2 = mainMenu.items.filter(){ $0.submenu!.title == "Word class" }[0]
let myItemSubmenu2 = firstMenu2.submenu?.items.filter(){ $0.submenu!.title == "Noun group" }[0].submenu
myItemSubmenu2?.item(withTitle: "Subject")?.isEnabled = true
myItemSubmenu2?.autoenablesItems = false // Even if no action defined, can be enabled
// To set the state:
let myItemSubject2 = myItemSubmenu2?.items.filter(){ $0.title == "Subject" }[0]
myItemSubject2?.state = .on // This switches the menu On