views:

114

answers:

3

Hi,

I'm distributing two different versions of one product (like light and pro version). I don't know how to use the same MainMenu.xib if I can not change the placeholder NewApplication in a dynamic way. I would like to use the bundle name instead of "NewApplication". I hope there is an official way to do this without hacking.

Thank you,

+1  A: 

You most likely want to use the multiple-targets route; use a single Xcode project with several build targets, one for your regular app and one for your lite version. See here. (And yes, this is officially supported in Xcode, and I know of several app developers who use this strategy to publish both versions of their app on the App Store.)

Tim
Tim, I have already two targets using the 'same' MainMenu.xib. This will not solve the problem with the menu bar. Both products (produced by the targets) will show the same menu items containing the string "NewApplication". And this is where I want to place the variable $(PRODUCT_NAME) of the targets.
cocoafan
Can you use a bunch of `#ifdef` and `#define` statements to specify a separate variable, like `MENU_DISPLAY_NAME`, and use that as your menu identifier?
Tim
+3  A: 

I'd do it like this:

NSMenu *menuBar = [NSApp mainMenu];
// we know that the application is always at the very left
NSMenu *applicationMenu = [menuBar itemAtIndex:0];
// we know that the quit-menu item is always the last element
NSMenuItem *quitMenuItem = [applicationMenu itemAtIndex:
                                  [applicationMenu numberOfItems] - 1];

quitMenuItem.title = [quitMenuItem.title
                    stringByReplacingOccurrencesOfString:@"NewApplication"
                                              withString:@"SomeOtherName"];

You could also set tags on the menu items you want to change.

Georg
The menu item at [menuBar itemAtIndex:0] is replaced by $(PRODUCT_NAME) automatically. So there is no need to replace it again. I was hoping to find a way to automate also the submenu items like "Quit NewApplication" without using stringByReplacingOccurrencesOfString:withString: :)
cocoafan
Please see also my own answer
cocoafan
BTW, [menuBar itemAtIndex:0]; will not return an NSMenu. It will return an NSMenuItem.
cocoafan
Haven't tried it, but `NSMenu` returns an object conforming to the `NSMenuItem` protocol which could also be an `NSMenu`. If my code works it is an `NSMenu` because only it has a `itemAtIndex:` method.
Georg
+2  A: 

Inspired from the answer of gs, here is what I have added to my code. I'm calling setupBundleNameInMenuBar in AppDelegate's awakeFromNib.

This code will replace all occurrence of "NewApplication" with the application name.

- (void)setupBundleNameInMenuBar {
    NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleNameKey];
    if (appName == nil) appName = [[NSProcessInfo processInfo] processName];

    NSMenu *menuBar = [NSApp mainMenu];
    for (NSMenuItem *menuItem in [menuBar itemArray])
        [self replaceTitlePlaceholderInMenuItem: menuItem withString: appName];
}

- (void)replaceTitlePlaceholderInMenuItem:(NSMenuItem *)root withString:(NSString *)appName {
    root.title = [root.title stringByReplacingOccurrencesOfString: @"NewApplication"
                                                       withString: appName];

    NSArray *submenuItems = [root.submenu itemArray];
    for (NSMenuItem *menuItem in submenuItems)
        [self replaceTitlePlaceholderInMenuItem: menuItem withString: appName];
}
cocoafan