Wednesday, March 9, 2011

Loading xib files in iPad/iPhone Universal app

Note: This blog is deprecated. @synthesize zach has moved to a new home, at zpasternack.org. This blog entry can be found on the new blog here. Please update your links.

I'm making an iPad enhanced version of PuzzleTiles, and have thus been doing a lot of reading on doing Universal apps.

One thing just about every Universal app has to do is to have separate xib files, because the iPhone and iPad have completely different form factors. I've stumbled across this idiom continuously in the past few days:

if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad){
    mainMenu = [[MainMenu alloc] initWithNibName:
                 @"MainMenu-iPad" bundle:nil]; 
}else{  
    mainMenu = [[MainMenu alloc] initWithNibName:
                 @"MainMenu" bundle:nil]; 
}

Well, that's all well and good, but it turns out that initWithNibNamed:bundle: supports device modifiers. So instead of the above, you can use this:

mainMenu = [[MainMenu alloc] initWithNibName:
             @"MainMenu" bundle:nil]; 

The magic is in the file naming. Name your files "MainMenu.xib" for the iPhone version and "MainMenu~ipad.xib" for the iPad version. iOS will automatically load the device-specific version when running on that device. Much easier, no?

I found no official Apple documentation which explicitly states that the device modifier mechanism works for xib files, but it definitely works, back to iOS 4.0, near as I can tell. Relevant StackOverflow question here. I'm always on the lookout for ways to remove code, so I'll take it.

Update: As noted below in the comments, device modifiers are case sensitive, so make sure you're doing "MyView~ipad.xib", not "MyView~iPad.xib", or else the magic won't work. Relevant Apple documentation here.