Unable to load two nib (.XIB) for Single ViewContr

2020-07-22 17:58发布

问题:

Sorry Guys in advance, I know there are already plenty similar questions are available. I tried all solutions but didn't work any of them for me.

I'm Using Xcode 4.5.2 and using two xibs for iphone5/ios6 1> RootViewController5 and for all other devices 2> RootViewController these both nib file has single ViewController named RootViewController.In both the nib file's File owner I have selected RootViewController class in Custom class inspector.

Now in ViewDidLoad method I'm trying to load two nibs like this

 if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
    {
        CGSize result = [[UIScreen mainScreen] bounds].size;
        UIViewController *viewController3;
        if(result.height == 480)
        {
          viewController3 = [[[UIViewController alloc] initWithNibName:@"RootViewController" bundle:nil] autorelease];
        }
        if(result.height == 568)
        {
        viewController3 = [[[UIViewController alloc] initWithNibName:@"RootViewController5" bundle:nil] autorelease];

            NSLog(@"iphone 5 123");
        }
    }

I have tried below code as well

 if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
    {
        CGSize result = [[UIScreen mainScreen] bounds].size;
        RootViewController *viewController3;
        if(result.height == 480)
        {
          viewController3 = [[[UIViewController alloc] initWithNibName:@"RootViewController" bundle:nil] autorelease];
        }
        if(result.height == 568)
        {
        viewController3 = [[[UIViewController alloc] initWithNibName:@"RootViewController5" bundle:nil] autorelease];

            NSLog(@"iphone 5 123");
        }
    }

But no luck. Please advise where I'm getting it wrong.

Thanks

Mayur

回答1:

I suggest you do something like this instead:

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    if([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone){
        if([UIScreen mainScreen].bounds.size.height == 568.0)
        {
            //Use iPhone5 VC
            self = [super initWithNibName:@"RootViewController-568h" bundle:nibBundleOrNil];
        }
        else{
            //Use Default VC
            self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
        }
    }
    return self;
}

That is if your RootViewController is named just that. And by doing it this way you save yourself from future crashes if they should decide to add another size of an iPhone/iPod. As you are using two if statements, if neither is true it will crash the app and is really not good coding.

A good practice is to always try and think ahead and plan for the future, if they should release another screen size it wouldn't look good but would at least not crash.



回答2:

The obvious problem I see from your description is that you set the custom class to "RootViewController" in your nib, but you are actually instantiating a "UIViewController" in your code.

What you should have done is:

viewController3 = [[[RootViewController alloc] initWithNibName:@"RootViewController" bundle:nil] autorelease];

Otherwise, when the runtime loads your nib, and is trying to set up those RootViewController specific outlets in your nib, the runtime won't be able to find those in a vanilla UIViewController, and so crashes.



回答3:

I don't think that you've to use two different .xib's for iPhone5 & iPhone4, 4S etc. If you want to change the sizes of your images, labels, buttons etc., that's why Spring and Structs are used for. You can also set the sizes programmatically by using the code you've written in your question (in your .m files....... )

I also have done that mistake before. When i used to run the program, i always came up with the error

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException',
 reason: '-[UIViewController _loadViewFromNibNamed:bundle:] loaded the "View" nib but
 the view outlet was not set.' *** First throw call stack:(0x1c93012 0x10d0e7e 0x1c92deb 
0xf58c8 0xf5dc8 0xf5ff8 0xf6232 0x453d5 0x4576f 0x45905 0x4e917 0x2b7f 0x12157 0x12747 
0x1394b 0x24cb5 0x25beb 0x17698 0x1beedf9 0x1beead0 0x1c08bf5 0x1c08962 0x1c39bb6 
0x1c38f44 0x1c38e1b 0x1317a 0x14ffc 0x25fd 0x2525 0x1)libc++abi.dylib: 
terminate called throwing an exception

This is because " nib outlet was not set"

So, i think you should either use Springs and structs or do programmatically..



回答4:

I would recommend you to :

use story board, instead of XIB files when you instantiate a VC, ex:

    myVC* vc = [self.storyboard instantiateViewControllerWithIdentifier:@"myVCStoryBoardID"];

[self.navigationController pushViewController:vc animated:YES];  

This helps keep VC design under the same roof, and to use powerful features of storyboarding.

Then to check that Auto-layout is active on your story board controllers, and insure that the constrains on one, say, label, map to the boundary of other elements (very important), above and below. This materialises by dotted blue lines when you move it. In most case, the run-time will be able to align everything, regardless of screen height.

I understand that there might be some nasty edge cases in this regards, so you might have to adjust stuff manually. Unless you have complex graphics, it's always possible to work with Y coordinate in the [0,1] interval, and once you have to set a frame, use [[UIScreen mainScreen] bounds].size to get the appropriate value, rounded to the nearest integer.

If all the above fails, then you might have to create separate VC, but in my view, that's not really what the SDK is intended for.

good luck!



回答5:

Wow, I was such a fool, I didn't realise that I wasn't loading the Nib Properly. Only thing I was wrong with is This line of code

I wrote viewController3 = [[[UIViewController alloc] initWithNibName:@"RootViewController5" bundle:nil] autorelease]; instead of

 [[NSBundle mainBundle] loadNibNamed:@"RootViewController5" owner:self options:nil];

So My Final code is look like this and Works absolutely fine

if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
    {
        CGSize result = [[UIScreen mainScreen] bounds].size;
        if(result.height == 480)
        {
            // iPhone Classic
            [[NSBundle mainBundle] loadNibNamed:@"RootViewController" owner:self options:nil];
        }
        if(result.height == 568)
        {
            // iPhone 5
            [[NSBundle mainBundle] loadNibNamed:@"RootViewController5" owner:self options:nil];
        }
    }

Thanks to this link Link to the right Answer