Sam Yeary
Sam Yeary

Reputation: 21

How do you programmatically call a viewcontroller get its view in the storyboard?

I am using a BookController class which is using pagenumbers to keep track of the current view. Currently I am creating each view controller on demand and writing the code programmatically. I would like to access the view controllers that I have created in the StoryBoard (the xib files) so that when I demand a new page it will access a Second view controller I have created.

// Provide a view controller on demand for the given page number

- (id) viewControllerForPage: (int) pageNumber {

if ((pageNumber < 0) || (pageNumber > 31)) return nil;


if(pageNumber == 0){

      //here is where I want to access the entire xib file that the SecondViewController is connected with     
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Storyboard" bundle:nil];
    SecondViewController *myVC = (SecondViewController *)[storyboard instantiateViewControllerWithIdentifier:@"SecondViewController"];

    myVC = [BookController rotatableViewController];

    return myVC;

     }
else if(pageNumber == 1){


// Establish a new controller
   UIViewController *controller = [BookController rotatableViewController];


// Add a text view
UITextView *textview = [[UITextView alloc] initWithFrame:(CGRect){.size = CGSizeMake(100.0f,100.0f)}];
textview.text = [NSString stringWithFormat:@"This is dedicated to people"];
textview.font = [UIFont fontWithName:@"Futura" size:18.0f];
textview.center = CGPointMake(475.0f, 700.0f);
[controller.view addSubview:textview];

     // Add a label
UILabel *textLabel = [[UILabel alloc] initWithFrame:(CGRect){.size = CGSizeMake(200.0f, 200.0f)}];
textLabel.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
textLabel.text = [NSString stringWithFormat:@"1"];
textLabel.font = [UIFont fontWithName:@"Futura" size:18.0f];
textLabel.center = CGPointMake(475.0f, 985.0f);
[controller.view addSubview:textLabel];


    // Add it as an image
    UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"[email protected]"]];
imageView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    imageView.center = CGPointMake(160.0f, 230.0f);
[controller.view addSubview:imageView];


return controller;
}

Just not sure how to make a call to access that xib file i've created and make it into the first page (page=0). The second page (page =1) is an example of how i have drawn all the other pages in my book programmatically. Thanks!

Upvotes: 2

Views: 2697

Answers (1)

Brennan
Brennan

Reputation: 11686

Remember the Storyboard is just a collection of NIBs which simply instantiate the hierarchy of each view and connect the outlets to the owning view controllers. You do not want to instantiate the Storyboard yourself to just create a single view controller. What that is doing is creating new instances when the application has already been launched and is running with different instances. Even if you did have them wired up they would be wired to instances which are redundant and not the actual instances you want.

What I would do instead is create an individual NIB file for SecondViewController which you will use separately. Then you will need to wire it together. If this code is within the instance you need to access you would simply pass it along to a property on SecondViewController. Or maybe you just pass along values but most likely you will want to set a delegate property and define a protocol for SecondViewController to call back to the instance which created it.

For your code you can simply load the NIB with the following code.

SecondViewController *vc = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil];
vc.delegate = self;

You just need to define that delegate and possibly any properties you need to give data to the newly created view controller.

Below is an example of a delegate setup which I recently created for a SideBar interface using a Storyboard. I have a container view for the Header VC which is in the Home VC. This Header VC could be like your SecondViewController because I could not connect it in the Storyboard so I did it with code. First I created a delegate property on the Header VC.

@protocol IFHeaderDelegate;

@interface IFHeaderViewController : UIViewController

@property (nonatomic, assign) IBOutlet id<IFHeaderDelegate> delegate;

@end

@protocol IFHeaderDelegate <NSObject>

- (void)headerViewDidToggleSideBar:(IFHeaderViewController *)sender;

@end

Then when a button is tapped I use the delegate for the callback. (Notice I use an NSAssert to verify the delegate is defined just to give me a heads up if I missed it.)

#import "IFHeaderViewController.h"

@interface IFHeaderViewController ()

@end

@implementation IFHeaderViewController

- (IBAction)siderBarButtonTapped:(id)sender {
    NSAssert(self.delegate != nil, @"Delegate must be defined!");

    if (self.delegate != nil) {
        [self.delegate headerViewDidToggleSideBar:self];
    }
}

@end

But in order to wire it up I had to set the delegate from the Home VC which I could not do from the Storyboard. What I did was set it in the Home VC when the embed segue was fired in prepareForSegue.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
   DebugLog(@"segue.identifier: %@", segue.identifier);

   if ([@"HomeHeader" isEqualToString:segue.identifier]) {
       NSAssert([segue.destinationViewController isKindOfClass:[IFHeaderViewController class]], @"Destination VC must be the Header VC");
       IFHeaderViewController *headerVC = (IFHeaderViewController *)segue.destinationViewController;
       headerVC.delegate = self;
   }
}

You can find the full project on GitHub: https://github.com/brennanMKE/Interfaces/tree/master/SideBar

Upvotes: 2

Related Questions