Apple did a fairly nice job with the @IBAction mechanism. It’s easy to add code to handle a menu item action in a macOS program. It’s the same with iOS for button taps and other UI actions. But with the menu items, there is a severe oversight that frustrated me for more than a few minutes; The only way to update menu items to enable or disable them, or to check or uncheck them, is to add a function called validateMenuItem(). The problem is that this function is called for every menu item and is passed a reference to the menu item object in question. How do I figure out what to do in this function, have a switch statement or “if” tests to figure out which item it is based on the action function? A switch statement or other test is completely unreasonable if there are more than a few menu items to handle.
Although it’s not possible to create a dictionary with functions as the key, because references to functions are not hashable (but should be?), it is possible to create a menu item reference for every menu item and then use these as keys for the dictionary. The value in the dictionary can then be a function to call to update that specific menu item.
Implementing my solution required that I create an @IBOutlet for each menu item. These are NSMenuItem variables in the AppDelegate class that are connected to the menu items stored in the MainMenu.xib file. After creating all of these, or at least a large set for the menu items I know are required, I added the necessary dictionary code to the WindowController.swift file for my program. The code is shown above and you can see that calling the appropriate function to update the state of the menu item will be quick due to the simplicity of using the dictionary. In the code above, I removed the 15 other menu items that are in the “Edit” sub menu to make the code more readable. In addition to there being 10 to 15 menu items in the edit menu, there will also be a “View” sub menu with 5 to 10 items and at least another 10 items in two or three other menus. The total of 30 or menu items make a switch statement or “if” test unreasonable. but what is most unreasonable in this situation is Apple not providing an API to handle this better.
There are alternatives and maybe I took the wrong approach. In my document class, there will be code that, for every change of the document, will update a set of variables that track what modifications are allowed. For instance, if the user selects a set of document elements in the UI, a flag will get set to indicate that cut, copy, delete, stretch, rotate, and numerous other functions, are available. It would be reasonable to update the menu items at that time and not alter them when the menu is displayed. I would consider doing things this way except that the Linkage program on the Mac will be written based on code for Windows and I want to keep the source code files as similar as possible between platforms.
So far, I can’t think of any other alternatives. And I’m a bit disappointed that I could not use the action functions for the dictionary since I have no other need for the 30+ @IBOutlets for the menu items. I’m a strong believer that the less code I can write, the better off I am and the better off my users will be when they run my programs.
And yes, I realize that I left my dictionary name as it’s original name before I knew that I could not use the action functions as the keys.