Xcode故事板容器视图 - 如何访问视图控制器

50

我正在尝试使用storyboard并使其正常工作。 我已将Container View添加到其中一个现有视图中。 当我尝试在视图控制器的.h文件中添加对此的引用(ctrl-drag)时,我得到了一个IBOutlet UIView *containerView。如何获取容器视图的视图控制器的引用? 我需要容器视图控制器,以便我可以将其委托给我的视图控制器,以便它们可以“交谈”。

我的故事板设置如下:

enter image description here

在我的.h文件中引用如下:

enter image description here

请注意,在.h中显示的是UIView,而不是我视图的InstallViewController。 如何添加对视图控制器的引用? 我需要能够设置其委托。


这是最终、终极、最后一篇、维护的教程!https://dev59.com/KGAg5IYBdhLWcg3wm7_6#23403979 你需要了解一些微妙之处,它们都在那里详细而清晰地解释了。 - Fattie
5个回答

70

通过为嵌入segue指定标识符并在prepareForSegue:方法中检索相应的视图控制器,可以有另一种解决方案。

这种方式的优点是你不需要依赖于子视图控制器添加的特定顺序,因为每个子视图控制器都是通过唯一的segue标识符嵌入的。

更新2013-01-17 - 示例

- (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_SegueIdEmbedMasterVCc_SegueIdEmbedDetailVC是常量,其对应的ID是在storyboard中定义的segue ID。


2
抱歉更新晚了。我相信你在此期间已经自己解决了问题,但最终示例代码会帮助其他人解决类似的问题。 - DAXaholic
2
上帝的回答。我之前尝试过那个技巧,但只有在阅读了这个答案后,我才意识到它只在设置了Segue标识符时才起作用。然而,我会使用isKindOfClass:。 - Yariv Nissim
为什么有两个视图控制器(详细和主控制器)?难道不是容器中只有一个视图控制器吗?你提到的其他segue是什么? - shim
1
@shim:在我的示例项目中,我有一种分割视图,其中主视图控制器和详细视图控制器托管在2个单独的容器视图中 - 因此有两个视图控制器。 - DAXaholic
很遗憾,这是获取对子视图控制器引用的最佳方式。 故事板的整个目的是减少像这样的样板代码。 我可以在更少的代码行中在viewDidLoad中添加子视图控制器,并且它比这更易于维护。 有人知道这是否在XCode 6中得到了修复吗? - Robert

14

当您添加容器视图时,Xcode会调用UIViewController方法addChildViewController:

在您的情况下,您可以通过查找SplashViewController的childViewControllers列表来获取容器视图控制器,例如:

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;
    }
}

昨天我也有同样的疑问 :)


1
我正在尝试做类似的事情,我不理解的是 "vc" 在 InstallViewController *installViewController = (InstallViewController *)vc; 中的含义。 - Pantelis Proios
你说得对,应该是“childViewController”。我已经在帖子中修复了。抱歉回复这么晚。 - vfranchi
1
这种方法对我来说感觉有点像“变通方法”。不是吗? - Javier Quevedo
做得好,它起到了作用 :) 当一个容器视图被添加到另一个视图中时,prepareForSegue方法会被调用吗? - vfranchi

2
Vitor Franchi的答案是正确的,但可以更加高效和方便。特别是在多次访问子视图控制器时。
创建一个只读属性。
@interface MyViewController ()
@property (nonatomic, weak, readonly) InstallViewController *cachedInstallViewController;
@end

然后创建一个方便的getter方法。
- (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;
}

从现在开始,可以通过这种方式访问子视图控制器。
[self.installViewController doSomething];

0
UIView* viewInsideOfContainer = installerView.subviews[0];

将为您提供UIViewController内的UIView,该控制器UIView引用。您可以将子视图转换为任何继承自UIView的类型。


我不确定我喜欢做出那种假设,但了解这一点很有用。 - jab
那不是通用的方法:视图层次结构可能会更改,这种方法将无法工作。 - silvansky

0
如果nib已加载,则它将在初始化过程中调用addChildViewController。
因此,一个高效的解决方案也可以是覆盖。
- (void)addChildViewController:(UIViewController *)childController

在那里,你可以通过比较其类别来捕获你的子控制器,并将其分配给一个属性/实例变量。

-(void)addChildViewController:(UIViewController *)childController
{
    [super addChildViewController:childController];

    if([childController isKindOfClass:[InstallViewController class]])
    {
        self.installViewController = (InstallViewController *)childController;
    }

}

这将避免您迭代子视图控制器。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接