Creating status item - icon shows up, menu doesn&#

2019-03-04 02:46发布

问题:

In a document-based project I am trying to create a status menu. I have a singleton class that builds the status bar, and I am initiating it from an application delegate, as you can see. When I run this, I get no errors, but only an image of the status bar, but no menu drops down. I created the menu in IB. What am I messing up?

Delegate

#import "KBAppDelegate.h"
#import "KBStatusMenu.h"

@implementation KBAppDelegate
@synthesize window = _window;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification 
{
    KBStatusMenu *aStatusItem = [[KBStatusMenu alloc] init];
    aStatusItem = [[KBStatusMenu instance] buildStatusItem];
}
@end

.h

#import <Foundation/Foundation.h>

@interface KBStatusMenu : NSObject 
{
    NSStatusItem *myStatusItem;
    NSImage *statusImage;
    IBOutlet NSMenu *myStatusMenu;
}

+ (KBStatusMenu *)instance;
- (id)buildStatusItem;

@end

.m

#import "KBStatusMenu.h"

@implementation KBStatusMenu
static KBStatusMenu *gInstance = nil;

+ (KBStatusMenu *)instance 
{
    @synchronized(self) {
        if (gInstance == nil)
            gInstance = [[self alloc] init];
    }

    return(gInstance);
}

- (id)buildStatusItem 
{
    myStatusItem = [[[NSStatusBar systemStatusBar]         statusItemWithLength:NSSquareStatusItemLength] retain];
    statusImage = [NSImage imageNamed:@"statusNormTemplate.png"];
    [myStatusItem setImage:statusImage];
    [myStatusItem setHighlightMode:YES];
    [myStatusItem setMenu:myStatusMenu];
    return myStatusItem;
}

@end

回答1:

You declared myStatusMenu as an outlet, but never loaded a nib (or assigned anything to it yourself). An outlet cannot get objects out of nowhere; the outlet is set only when you load a nib that has the outlet connected to something (or assign something to the variable yourself, as if it weren't an outlet).

You can prove this by adding a line to buildStatusItem that logs the value of the myStatusMenu instance variable. I expect that it will be nil.

What you need to do is:

  1. Create a nib to contain the status item's menu.
  2. Set the class of the File's Owner to KBStatusMenu.
  3. In KBStatusMenu, implement init to load the nib you just created.

Then, by the time you reach buildStatusItem, loading the nib will have set the outlet, and you will have a menu to give to your status item.

I would recommend only creating one KBStatusMenu instance. In this case, I recommend enforcing the singleton: init should test whether gInstance has already been set and, if so, return that; only if it hasn't should it initialize and return self.