Question

I have a menu item inside the main app menu and I’d like to route its action to a view controller (NSViewController). The interface hierarchy looks like this: There’s a main app window controller by an NSWindowController. Inside the window there’s a split view, and the right view in the split view is controlled by the NSViewController.

Window + NSWindowController
    `-- NSSplitView
           `-- NSView
           `-- NSView + NSViewController

The menu item is connected to First Responder in the Interface Builder. The view controller in question implements the appropriate method, but the menu item stays disabled. When I move the method to the NSWindowController, the menu item gets enabled.

I figured I need to get the view controller to the responder chain, so I set it as the nextResponder for the window controller; no cigar. What am I doing wrong?

Was it helpful?

Solution

In the end I added a base class for my window controllers and made it forward calls to the “child” controllers:

- (id) childControllerForSelector: (SEL) selector
{
    for (id controller in [childControllers copy])
        if ([controller respondsToSelector:selector])
            return controller;
    return nil;
}

- (BOOL) respondsToSelector: (SEL) selector
{
    return [super respondsToSelector:selector] ? YES :
        [self childControllerForSelector:selector] ? YES :
            NO;
}

- (void) forwardInvocation: (NSInvocation*) invocation
{
    id child = [self childControllerForSelector:[invocation selector]];
    [invocation invokeWithTarget:child];
}

- (NSMethodSignature*) methodSignatureForSelector: (SEL) selector
{
    NSMethodSignature *signature = [super methodSignatureForSelector:selector];
    if (!signature) {
        id child = [self childControllerForSelector:selector];
        signature = [child methodSignatureForSelector:selector];
    }
    return signature;
}

It’s a lot of code, but it’s a general solution that keeps the controller code free from ad-hoc forwarding. Hopefully it’s not too much magic.

OTHER TIPS

You can set the window controller as the delegate of the window so it will now be a part of the responder chain.

Assuming that you have your own subclass of NSWindowController, you can then simply catch the menu event there and call your appropriate methods in your controllers.

Unfortunately, the docs advice against trying to insert anything in the responder chain between the various views and subviews, so you can't just squeeze your view controller in there.

More here, but I take it you have already consulted that.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top