xcode storyboard Container View - How do I access the viewcontroller

25,046

Solution 1

There is another solution by specifying an identifier for the embed segue(s) and retrieve the corresponding view controllers in method prepareForSegue:

The advantage of this way is that you needn't rely on a specific order in which your child view controllers are added due to the fact that each child view controller is embedded via an unique segue identifier.

Update 2013-01-17 - Example

- (void) prepareForSegue:(UIStoryboardSegue*)segue sender:(id)sender
{
    // -- Master View Controller
    if ([segue.identifier isEqualToString:c_SegueIdEmbedMasterVC])
    {
        self.masterViewController = segue.destinationViewController;
        // ...
    }
    // -- Detail View Controller
    else if ([segue.identifier isEqualToString:c_SegueIdEmbedDetailVC])
    {
        self.detailViewController = segue.destinationViewController;
        // ...
    }
}

c_SegueIdEmbedMasterVC & c_SegueIdEmbedDetailVC are constants with the corresponding ID of the segue IDs defined in the storyboard.

Solution 2

When you add a container view the xcode calls the UIViewController method addChildViewController:

In your case, you can get the container ViewController looking for it on the SplashViewController's list of childViewControllers, something like this:

for (UIViewController *childViewController in [self childViewControllers])
{
    if ([childViewController isKindOfClass:[InstallViewController class]])
    {
        //found container view controller
        InstallViewController *installViewController = (InstallViewController *)childViewController;

        //do something with your container view viewcontroller

        break;
    }
}

I had the same doubt yesterday :)

Solution 3

The answer of Vitor Franchi is correct but could be more performant and convenient. Especially when accessing the child view controller several times.

Create a readonly property

@interface MyViewController ()
@property (nonatomic, weak, readonly) InstallViewController *cachedInstallViewController;
@end

Then create a convenient getter method

- (InstallViewController *)installViewController
{
    if (_cachedInstallViewController) return _cachedInstallViewController;

    __block InstallViewController *blockInstallViewController = nil;
    NSArray *childViewControllers = self.childViewControllers;
    [childViewControllers enumerateObjectsUsingBlock:^(id childViewController, NSUInteger idx, BOOL *stop) {

        if ([childViewController isMemberOfClass:InstallViewController.class])
        {
            blockInstallViewController = childViewController;
            *stop = YES;
        }
    }];

    _cachedInstallViewController = blockInstallViewController;

    return _cachedInstallViewController;
}

From now on access the child view controller that way

[self.installViewController doSomething];
Share:
25,046
Justin808
Author by

Justin808

Just some guy on the interwebs.

Updated on August 03, 2020

Comments

  • Justin808
    Justin808 almost 4 years

    I'm trying to use storyboard and get things working properly. I've added a a Container View to one of my existing views. When I try to add a reference to this in my view controller .h file (ctrl-drag), I get a IBOutlet UIView *containerView. How do I get a reference to the container view's view controller instead? I need the container view controller so I can set it's delegate to my view's controller so they can "talk" to each other.

    I have my story board setup as:

    enter image description here

    And its referenced in my .h file as:

    enter image description here

    Notice in the .h that is is a UIView, not my InstallViewController for the view. How do I add a reference to the view controller? I need to be able to set its delegate.

  • Pantelis Proios
    Pantelis Proios over 11 years
    I am trying to do something similar and what i don't get is the "vc" in InstallViewController *installViewController = (InstallViewController *)vc;
  • DAXaholic
    DAXaholic over 11 years
    Sorry for the late update. I'm sure you managed the problem by yourself in the meantime but eventually the example code helps other ones in the future.
  • vfranchi
    vfranchi about 11 years
    You are right, it should've been "childViewController". I've just fixed in the post. Sorry for taking that much to reply.
  • Yariv Nissim
    Yariv Nissim about 11 years
    God answer. I Tried that trick before, and only after reading this answer I realized that it only works if you setup Segue Identifiers. However I would use isKindOfClass: instead.
  • Javier Quevedo
    Javier Quevedo about 11 years
    This approach feels a bit like a "workaround" to me. Doesn't it?
  • vfranchi
    vfranchi almost 11 years
    Well, it did the trick :) Does the prepareForSegue method is called when a Container View is added to another view?
  • jab
    jab over 10 years
    I'm not sure I like making that assumption, but it's useful to know.
  • silvansky
    silvansky about 10 years
    That's not the universal way: view hierarchy can change and this method won't work.
  • shim
    shim almost 10 years
    Why are there two view controllers (detail and master)? Isn't it just the one view controller in the container? What other segue are you referring to?
  • DAXaholic
    DAXaholic almost 10 years
    @shim: In my example project I had a kind of split view with a master and a detail view controller hosted in 2 separate container views - therefore the two view controllers.
  • Robert
    Robert almost 10 years
    Its a shame that this is the best way of getting a reference to the child view controller. The whole point of the storyboards is to reduce boilerplate code like this. I could add the child view controller in viewDidLoad in fewer lines of code and it would be more maintainable than this. Anyone know if this fixed in XCode 6?