lmirosevic
lmirosevic

Reputation: 16317

C preprocessor macro that turns string into token?

I am trying to write a C preprocessor Macro for LLVM that's used like:

vc(@"Browser")

and expands to:

[[BrowserViewController alloc] initWithNibName:@"BrowserViewController" bundle:nil]

The best I can come up with is:

vc(Browser)

which is implemented as:

#define vc(xibName) [[xibName ## ViewController alloc] initWithNibName:[NSString stringWithFormat:@"%@ViewController", @#xibName] bundle:nil]

however to the user this could seem confusing as Browser on its own (outside of string literals) looks like a token. @"Browser" would make the intent a little clearer without requiring the user to read the macro.

EDIT:

The motivation behind this seems silly at first glance, but I work on apps for iPhone, iPad and OS X and each has it's own way of instantiating a view controller with a view that is laid out in Interface Builder.

iPad:

[[UIStoryboard storyboardWithName:@"StoryboardPad" bundle:nil] instantiateViewControllerWithIdentifier:@"Browser"];

iPhone:

[[UIStoryboard storyboardWithName:@"StoryboardPhone" bundle:nil] instantiateViewControllerWithIdentifier:@"Browser"];

OS X:

[[BrowserViewController alloc] initWithNibName:@"BrowserViewController" bundle:nil]

Since it's all Objective-C, some of my controllers are reused across platforms, and I don't like to litter my code with conditional compilation statements every time I want a view controller. Plus when working on different platforms on different days of the week it helps to know you can just call vc(@"Browser") and you'll get what you expect whether it's on and iPad, iPhone or MAC. It's just a question of convention vs configuration.

Upvotes: 0

Views: 289

Answers (2)

lmirosevic
lmirosevic

Reputation: 16317

Turns out a function is the way to implement this:

id InstantiateViewControllerWithXib(NSString *xibName) {
    NSString *className = [xibName stringByAppendingString:@"ViewController"];
    return [[NSClassFromString(className) alloc] initWithNibName:className bundle:nil];
}

To strictly answer the question, you could then define the desired macro:

#define vc(xibName) InstantiateViewControllerWithXib(xibName)

Upvotes: 0

Paul.s
Paul.s

Reputation: 38728

If you just call

[[BrowserViewController alloc] init];

then UIViewController will search for a xib with an appropriate name in the following way

  1. If the view controller class name ends with the word “Controller”, as in MyViewController, it looks for a nib file whose name matches the class name without the word “Controller”, as in MyView.nib.

  2. It looks for a nib file whose name matches the name of the view controller class. For example, if the class name is MyViewController, it looks for a MyViewController.nib file.

The above one line of code should be short enough to not justify a macro ;)

Upvotes: 2

Related Questions