iOS: Using device modifiers for loading xib files? - iphone

You can use a device modifier (i.e., ~ipad) to provide a device-specific key in Info.plist, and to specify a device-specific launch image (Default.png for iPhone, and Default~ipad.png for iPad, for example). Those two things are specifically mentioned in Apple Docs, but they don't say that this will work for any other kinds of files.
I've discovered (quite by accident) that this works for loading .xib files via initWithNibName:bundle:. So for example, I can have MyView.xib and MyView~ipad.xib, and this code:
MyViewController *viewController = [[MyViewController alloc]
initWithNibName:#"MyView" bundle:nil];
... will totally load MyView~ipad.xib on an iPad, and MyView.xib on other devices.
So, 1) Is this documented somewhere? I sure couldn't find it any any Apple docs. It's sure handier than checking UI_USER_INTERFACE_IDIOM() and hardcoding two different nib names everywhere, but I kinda don't trust it if it isn't documented.
And, 2) Does anyone know what version of iOS this started working in? I've only tried it in 4.2, and it works there. Device modifiers in general (even for the documented things listed above) are 4.0 minimum.

I had this same problem. The answer didn't make sense at first, but the good news is that it's easy to do! :)
Just name your iPad xibs without any modifier and your iPhone xibs with ~iphone modifier and it'll select them correctly.
So, with MyViewController, you'll have MyViewController.xib for the iPad and MyViewController~iphone.xib for the iPhone. Then you can just init your view controller with simple alloc/init.
[[MyViewController alloc] init] and it'll grab the right xib.
So, when I create a new view controller in XCode, I always choose the box to format it for ipad, because the xib it will create will be named MyViewController.xib and you want that one to be the iPad sized xib. Then I create a second xib, formatted for iPhone and name it with the ~iphone modifier.
The documentation is a little contradictory at times, but this page talks about how resources with an identifier will default to iPad.
ImageSoundResources
Check the section about using high res images. I know we're talking xibs and not images, but it does work. My last 6 apps have all used this idiom.

Actually, it is explicitly defined in the docs, but as a footnote.
CocoaNibs
In the note at the bottom of "Loading NIB files using NSBundle":
Note: If you are developing a
Universal application for iOS, you can
use the device-specific naming
conventions to load the correct nib
file for the underlying device
automatically. For more information
about how to name your nib files, see
“iOS Supports Device-Specific
Resources.”
Which links to Cocoa Conceptual LoadingResources
However, yes, this is a 4.0+ only feature.

I hate to be that guy and answer my own question, but I think the answer is:
1) Nope, not explicitly documented in any Apple documentation, and
2) 4.0 and higher (this based on my own testing)
All you really save is a couple lines of code checking for UI_USER_INTERACE_IDIOM(). Still, I'll take it. Less code is less code.

The appropriate technique to use in iOS 3.2 and later is the UI_USER_INTERFACE_IDIOM() function. I typically use a ternary operator to init the UIViewController with the appropriate XIB.
UIViewController* controller = [[UIViewController alloc]
initWithNibName:UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad ?
#"YourViewController-iPad" : #"YourViewController" andBundle:nil];

Related

How To Port an iPad Application to the iPhone

I have an existing iPad - Application, no I want to make an universal App.
There are many Tutorials with making iPhone Apps universall, but i dont find how to make iPad apps Universal. Is there somebody having experienxce with this?
No Storyboards are used, yust normal xib.
I've readed this tutorial, and porting iPhone apps to universal seems to be better supported by xcode:
http://www.raywenderlich.com/1111/how-to-port-an-iphone-application-to-the-ipad
I would think that the basic idea would be the same, whether you were converting an iPhone app to a universal app, or an iPad app to a universal one(?)
Set the iOS application target to "Universal".
If a view controller, say, XYZViewController has an associated xib for its UI, then - when you create a xib for the iPhone interface - append ~iphone to the name of the iPhone interface and ~ipad to the iPad one, i.e. their file names are
XYZViewController~iphone.xib and XYZViewController~ipad.xib. That way the right xib will be picked up if you pass nil or #"XYZViewController" as nib name to the designated initializer for the view controller. (It's worth noting that the same IBOutlet can be hooked up to the corresponding UI elements in both xibs simultaneously.)
In code, whenever you need to use a different display metaphor that depends on the device type (say you want to use , check for the device type through the test
if ([UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{ ... } else { ... }
Another place where you might want to use this test is in VC's shouldautorotatetointerfaceorientation: method.

Return to mainview from webView deployed using storyboard

I created a new project "Single View Application" and designed the mainView with Storyboard. My main view contains a UIButton that opens the camera, the camera scans barcode and automatically goes to a website. Now I created a webView programmatically so that website can open and also created a UIButton inside the webView. Now I want that UIButton to act as home botton and return to mainview. I am unable to do that, please help.
ViewController.m code: http://cl.ly/FKj8
My storyboard looks like:
You really should look into the View Controller Programming Guide -- by switching around the contents of a single view controller, you're making a lot of extra work for yourself with little benefit. By using multiple view controllers when you want to have different "screens" in your app, you can take advantage of storyboarding for easier development, and you automatically get better memory management (read: less potential for crashes), too.
However, to more directly answer your question... if you're putting the WebView into the view hierarchy with [self.view addSubview:webView], you can remove it with [webView removeFromSuperview]. (This means you'll have to keep a reference to the WebView around so you can refer to it when you want to dismiss it.)
I also noticed in the code you posted to cl.ly an unrelated method -deviceModel which uses uname() to get device information. This is a bad idea, for two reasons:
uname() isn't guaranteed to do something useful on an iOS device (even if it currently does). Use the UIDevice class instead if you need this kind of info, or...
Generally, you don't want to test for the device name to enable functionality in your app; instead, you should test for the capabilities you need. (For example, if you look for a device name starting with "iPhone 4" to test for a Retina display, you'll miss the 4th-generation iPod touch, and the iPhone-5-or-whatever-they-call-what's-next. Instead, use the UIScreen class.)

Updating iPhone app to Universal: IBOutlets

First off, I will say i've spent 6 hours on this topic and have read everything the internet has to provide, which is why i came here.
I have converted to Universal, Xcode created the MainWindow-iPad.xib and everything seems fine.
Here are my questions:
1) What are the naming conventions for new iPad-specific xibs? Xcode created "-iPad" but i believe im supposed to be making them "~ipad". Why the difference?
2) (MOST IMPORTANT) After creating several "~ipad" xibs, Xcode seems to know to load these. So I'll copy the content in say, "RootViewController.xib"
and paste it in "RootViewController~ipad.xib". THIS IS THE PROBLEM: this new ~ipad xib has no outlets or referencing outlets!
I can't link the buttons on my page to anything. How do i do this without having a separate ~ipad .m and .h for everything?
Thank you guys for your help! I'm going to write a tutorial on this once I get this all working.
Just set the class of that ~iPad nib to be the same classname as the cooresponding iPhone nib. This is done in the inspector in Interface Builder. You may have to connect the outlets back up depending on the order you do things. I would think that if you copy the objects from the iPhone nib to the iPad nib AFTER you set the class, then the outlets would stay wired up.

Converting an iPhone app to a Universal app?

I have an iPhone app with
FirstViewController and SecondViewController with respective views FirstView.xib and SecondView.xib.
Now I want to make this app work with both iPhone and iPad. For iPad I need to merge Firstview.xib and SecondView.xib into a single ThirdView-iPad.xib.
What would be the best approach? Do I need to write another ViewController class for iPad or can I use existing FirstViewController and SecondViewController with single xib?
My research so far says that there is no way to use multiple ViewControllers with single xib. Please let me know the best way to do this.
Thanks
if you are using Xcode4 you can use "transition to universal target" and it will do everything needed
http://xcodebook.com/2011/05/making-an-ios-target-universal/
if you dont have it then I recommend to keep controllers out of your xib. xib files will be only containing views for iphone and ipad but the controllers "can" be same. and you can control your logic from the rootviewcontroller, just an idea..it all depends on your project.
You would be best of to just create a new ViewController unless you're into masochism. Reusing in that way would most likely be to much trouble, and I'd go with aggregation or inheritance in the case you need to reuse logic in your ViewControllers.
I typically create a base ViewController, say XYZViewController and then create a XYZViewController_iPhone with all iPhone-specials and a separate XYZViewController_iPad for iPads. But if they're totally different I give them unique names and their own NIBs as well as ViewControllers.
There Are following Rules To Convert The Iphone App to Univarsal App
1) In Plist File Add NSMainNibFile~ipad .... MainWindow_ipad(ipad window).
2) Implement separate Names Xibs (Iphone & ipad)
3)in Target Targeted Device Family set to (iphone/ipad)
and set The Frames According To Ipad &iphone
For example
if(UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPad)
{
btnHme.frame=CGRectMake(971,6, 32, 32); //ipad
}
else
{
btnHme.frame=CGRectMake(438,6, 32, 32); //iphone
}
cheers

find xib for iPad

I load my xib files through: initWithNibName programatically. If I set something like: [[LoginController alloc] initWithNibName:#"LoginController" bundle:nil];
Shouldn't it load LoginController.xib if it is executed on iPhone and search for LoginController-iPad.xib on the iPad? This is not happening at my code, do I have to select the right one manually or is something going wrong?
Thanks in advance!
No, there is nothing in the documentation that suggests "-iPad" is a valid resource-like modifier for initWithNibName:, or that initWithNibName: supports modifiers at all.
BTW, .xib files are compiled to .nib files by Xcode, so the application never sees a .xib.
This is an old question, so perhaps this naming convention did not exist when #shaggy frog answered this question, but iOS should indeed load the iPad specific xib if it is named correctly. In this case your naming is slightly off, the correct naming scheme for an iPad specific xib is
NameOfYourViewController~ipad.xib
Note that it's a tilde (~) instead of a dash (-) and ipad is in lowercase.