Best way to wire up NSMenuItems from Interface Builder?
So I've spent some time checking out CocoaDev, reading the Cocoa docs on NSMenuItems, and doing some tests in Interface Builder.
In my application I have an application menu ([NSApp mainMenu]) designed in Interface Builder. I see three potential paths:
Put my action responders in the NSApplicationDelegate. This seems strange to me, partially because it's so far up the food chain, partially because it seems bolted on.
开发者_运维知识库Create a sub-view(s) that would listen for the various NSMenuItem action messages. This would seem useful but it looks like in order for it to be in the responder chain there might be some magic I couldn't figure out.
Create an NSObject that listens for the specific application menu stuff, put it in the xib, and wire it up. This seems to me the best solution at the moment, because I can isolate stuff, and not depend upon the responder chain to reach a specific object. BUT I wonder if, when I get my app to a sufficient level of complexity, this may be a problem because it usurps the responder chain, which is there for perhaps a reason beyond just ease of use.
Sorry for the long question. Is there a preferred approach? Thanks!
It really depends on the architecture of your application. As a general rule, implement actions wherever they make sense. The responder chain for action messages helps you in that regard.
If your application isn’t document-based, the responder chain for action messages goes like this:
- Whichever responder is the first responder
- View hierarchy
- Window
- Window controller
- Window delegate
NSApp
- Application delegate
I only use actions in the application delegate if they’re truly global for the entire application. Otherwise, I put them in the window controller (which is normally the window delegate as well) if they make sense for a specific window, or a view controller if they make sense for a specific view.
It’s worth mentioning that view controllers (subclasses of NSViewController
) aren’t automatically inserted in the responder chain. I do that manually after adding the corresponding view to a superview. For instance, in an NSViewController
subclass:
NSResponder *nextResponder = [[self view] nextResponder];
[[self view] setNextResponder:self];
[self setNextResponder:nextResponder];
This inserts self
(an instance of a subclass of NSViewController
) in the responder chain between the view and the original view’s next responder.
Note that there’s nothing inherently wrong with your third approach, namely having a specific target for (a subset of) action messages. The responder chain exists to give a chance for different objects to handle action messages because some actions can be context-dependent. For example, the actions under the File menu are normally applied to the window that’s currently the main window, so it makes sense to not have a specific target and use the responder chain instead. On the other hand, the actions under the ApplicationName menu are truly global—they don’t need to go through the responder chain, so you can hook them up to a specific target.
I usually just expose IBActions
in the app controller (NSApp
delegate), and wire the menu items up to those actions. This is a pretty standard way of doing things. If you have a lot of menu items, you can also break the functionality up into one or more controllers that are connected to the app controller, and wire the menu items up to them.
精彩评论