Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loading a nib file inside a UIViewController

I'm experimenting on how to load nib files to a UIViewController.

I have created a separate nib file called Email. First I noticed that when the view controller is loaded, the initWithNibName method isn't getting called. So I called it from the viewDidLoad method manually like this,

[self initWithNibName:@"Email" bundle:[NSBundle mainBundle]];

It did not work. Also I got a warning saying Expression result unused.

And I searched on the internet and came across this article and implemented the loadView method as described like so,

- (void)loadView
{
    [super loadView];

    UINib *nib = [UINib nibWithNibName:@"Email" bundle:nil];
    [nib instantiateWithOwner:self options:nil];
}

The method gets called but still the view controller is empty!

Can anybody tell me what I'm overlooking here and how this can be done?

Thank you.

UPDATE:

First off, thanks for all the responses. However voromax and svena's answers suggest that I should remove segues and load nibs automatically which I'm not very fond of. Anil's answer works find and now I have one last hurdle to jump.

I have multiple nib files. Depending on the user's selection, it should load a specific nib. So what I tried was, put all the nibs inside the array like so,

- (void)loadView
{
    [super loadView];

    NSArray *nibs = [[NSArray alloc] initWithObjects:
                     [[NSBundle mainBundle] loadNibNamed:@"Facsimile" owner:self options:nil],
                     [[NSBundle mainBundle] loadNibNamed:@"Email" owner:self options:nil],
                     [[NSBundle mainBundle] loadNibNamed:@"Memorandum" owner:self options:nil],
                     [[NSBundle mainBundle] loadNibNamed:@"ProjectMemo" owner:self options:nil], nil];


    self.view = [nibs objectAtIndex:0];
}

and access it using its index like this self.view = [nibs objectAtIndex:1];. But it throws an error *Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayM _setViewDelegate:]: unrecognized selector sent to instance 0xd56fd20'*

Why is this error coming up? If its not possible, I'm open to suggestions.

Thanks again. And sorry for kinda dragging this out a bit.

like image 668
Isuru Avatar asked Apr 05 '13 07:04

Isuru


3 Answers

Use the below code to load a view from the nib and use as the view controller's view

- (void)loadView
{ 
[super loadView];

NSArray *nib =[[NSBundle mainBundle]loadNibNamed:@"test" owner:self options:nil];
self.view = [nib objectAtIndex:0];
}  

Edit

Load a single nib according to the user selection. See loading of a single nib

    NSArray *nib =[[NSBundle mainBundle]loadNibNamed:@"test" owner:self options:nil];  

will returns an array of objects. From your updated question I can see you are storing these arrays into another array. Now your nib array is an array of 'array' objects.

 self.view = [[nibs objectAtIndex:0]objectAtIndex:0]; 

will work.

But it is not good, load a single nib according to the user choise

like image 77
Anil Varghese Avatar answered Oct 14 '22 06:10

Anil Varghese


You are not supposed to load a nib for the view controller from within the methods of that view controller.

If you want to instantiate a view controller from nib, you do that from outside of that view controller, usually the view controller that presents it.

If you are looking for a hook inside presented view controller that would already have the outlet connections set up, overriding -awakeFromNib is a popular choice. -viewDidLoad is another.

Update #1

- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
{
   if ( /*do your segue identification stuff*/ ) {
      UIViewController *myViewController = /*init your view controller here*/
      UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:myViewController];
      [self presentViewController:navigationController animated:YES completion:nil];
      return NO;
   }
   return YES;
}
like image 22
svena Avatar answered Oct 14 '22 06:10

svena


You should use the nib file to instantiate the view controller itself i. e.

UIViewController *ctrl = [[UIViewController alloc] initWithNibName:@"Email" bundle:nil];

After that you can present this controller

Update

In case if you need to select which view controller should be loaded by the application logic it is better to create all view controllers in one storyboard, skip the hard segue binding and use instantiateViewControllerWithIdentifier: method of your storyboard instance to get the appropriate view controller and present it manually. I assume that your table view controller is already in navigation controller:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    if (APPROPRIATE_INDEX_PATH) {
        UIViewController *ctrl = [self.storyboard instantiateViewControllerWithIdentifier:IDENTIFIER];
        [self.navigationController pushViewController:ctrl animated:YES];
    }
}
like image 23
voromax Avatar answered Oct 14 '22 05:10

voromax