将子视图控制器链接到故事板内的父视图控制器

问题描述:

您可以将子视图控制器与Storyboard中的自定义容器视图控制器关联吗?将子视图控制器链接到故事板内的父视图控制器

我可以将子视图控制器链接到选项卡视图控制器,并且我可以将一个视图控制器链接到导航控制器。

容器风险投资接受儿童风险投资公司必须做什么?

正如迦勒和马特的答案组合的东西,我所做的:

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 
    if ([segue.identifier isEqualToString:@"cpdc_check_embed"]) { 
     self.checkVC = segue.destinationViewController; 
    } 
} 

...其中checkVC是容器控制器的特性:

@property (weak,nonatomic) PXPCheckViewController * checkVC; 

你只需要设置你的embed SEGUE的Storyboard ID到任何你想要的(在这种情况下,cpdc_check_embed):

check embed screen in Xcode

...然后检查-prepareForSegue:sender:中的标识符。

还没出口,但比马特的(恕我直言),比迦勒的更清洁,更具体的,你仍然可以得到一个好看的故事板:

enter image description here

+1

您正在使用嵌入式segue,这是一个iOS 6功能。我的问题从2011年11月开始。:-p –

+0

是的。刚刚意识到我正在让猫从袋子里出来一点。试图安装到客户端的5.1.1电话;没有骰子。 –

+1

现在iOS 6已经发布,这是正确的答案。 – awolf

您可以将子视图控制器与Storyboard中的自定义容器视图 控制器关联吗?

我想你在这里问的是如何将一个场景中的视图控制器连接到不同场景中的视图控制器的出口。我不相信这是可能的,也许是因为故事板机制可能没有同时加载故事板中的所有场景。

你可能会问这是因为你想从一个视图控制器传递一些信息到另一个视图控制器,从一个场景到下一个场景。当您使用故事板时,执行此操作的方法是在一个或两个受segue影响的视图控制器中覆盖-prepareForSegue:sender:。参数segue中提供的UIStoryboardSegue对象具有sourceViewControllerdestinationViewController属性,还有identifier属性。您可以使用这些属性来识别即将在视图控制器之间传输数据的segue。

雷Wenderlich的博客对使用故事板,可以帮助您一个不错的两部分教程:

  • Part 1包括设立一个故事板项目,添加场景,并创造塞格斯。

  • Part 2涉及使用段落在场景之间转换,包括上述prepareForSeque方法。

的iOS 5允许多个视图控制器是活跃在同一场景中(尽管仍然应该负责),所以在你的故事板一个场景可能有几个控制器。您可以使用插座将这些控制器相互连接,并且可以按照您在IB中所做的相同方式配置这些连接:控制 - 在同一场景中从一个控制器拖动到另一个控制器。通常的插座列表将弹出以让您选择要连接的插座。

+1

不,我的意思是同时使用两个视图控制器。包含多个_child_视图控制器的_container_视图控制器。类似于分割视图控制器,它包含主视图控制器和详细视图控制器,但是分割视图控制器(父VC)的子项。 –

+3

在这种情况下,只需将NSObject从库中拖到要包含子视图控制器的场景的扩展坞中即可。将对象的类型设置为您的视图控制器类。之后,您可以通过拖放控件与其他对象(包括场景中的其他视图控制器)建立连接。如上所述,你不能做的是在不同场景中的对象(视图控制器或其他)之间建立连接。 – Caleb

+0

因此,与Apple的容器视图控制器不同,如果我想同时显示它们,所有视图控制器(子视图和父视图)必须位于同一场景中。那么,它完成了这项工作,这就是我想要的。谢谢! –

在一个场景中使用多个控制器的关键(我相信你在这里之后)是使用IB中Objects对象列表中的神秘对象来表示另一个视图控制器并连接它的插座。

这个答案How to create custom view controller container using storyboard in iOS 5应该对我有所帮助。答案还提供了一个有用的示例应用程序。

故事板非常好地处理内置容器视图控制器,向子/根视图控制器显示segues,以便清晰地显示关系。儿童和父视图控制器如何分离成不同的场景也很好。

如果你想在你自己的项目中实现这种效果,那么有一个技巧并不完美,但非常简单。在我的例子中,假设我有一个容器视图控制器,它像一个标签栏控制器,只有两个选项卡,'左'和'右'。我想要一个场景表示父视图控制器,并且两个单独的场景表示“左”子视图控制器和“右”子视图控制器。

即使这是不可能的,如果我可以在容器视图控制器中创建IBOutlet到不同场景中的子元素,然后显示容器视图控制器时,将会很好设置父/子关系。该规则描述了UIViewController documentation。如果我们引用了我们的'左'和'右'子视图控制器,那么我们可以建立关系没有问题。

此引用问题的标准解决方案是通过将Object出口拖入容器视图控制器的场景中,然后将它们的类类型指定为子视图控制器类的实例来创建对子视图控制器的引用。

然而,为了让孩子们分离出不同的场景,像苹果的内置容器,我们将使用不同的技巧。首先,假设我们已经在容器类中声明了以下属性,ContainerViewController

@property (nonatomic, strong, readwrite) UIViewController *leftViewController; 
@property (nonatomic, strong, readwrite) UIViewController *rightViewController; 

在我们的故事板,选择代表的“左”视图控制器现场。在属性检查器中,将视图控制器的identifier属性设置为"cvc_leftViewController"(“cvc_”指的是ContainerViewController,但确实标识符可以是任何您想要的)。对正确的视图控制器的场景做同样的事情,把它的标识符设置为"cvc_rightViewController"

现在,插入下面的代码ContainerViewControllerviewDidLoad方法:

if (self.storyboard) { 
    _leftViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"cvc_leftViewController"]; 
    _rightViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"cvc_rightViewController"]; 
} 

ContainerViewController从故事板加载,它会抢‘从各自的场面左’和‘右’视图控制器和通过其属性设置对它们的引用。既然您已经控制了子视图控制器实例,那么您可以设置父/子关系。要了解如何正确执行此操作,请参阅UIViewController documentation

这个诀窍并不完美,并且有许多警告,但是如果您小心翼翼,您可以使它适合您的项目。

编辑:虽然这是完全不必要的,也不意味着什么,如果你真的真的希望有孩子的视图控制器,就像苹果公司的从你的容器故事板显示连接内置容器中,就用我的方法,然后在容器场景和子场景之间直接设置segues,并且不要执行那些segues。现在一切都会正常工作,看起来也很漂亮。

+1

+1听起来是一种很好的技术,你说得对,它模仿了Apple的容器视图控制器在故事板中的工作方式。与在容器相同的场景中创建子视图控制器相比,主要缺点是无法在场景之间建立连接。所以,如果你想设置一个子控制器的委托给父控制器,你必须在代码中这样做 - 你不能只拖动一个连接。 – Caleb

+1

是的。另外,我总是会因标识符串的连接而感到有些紧张,而不是网点带来的稳定感。 – Matt

+0

酷黑客!我将在现有的iOS 5应用程序中使用它。我的项目将变得更简单。苹果公司解决了我对iOS 6的问题(在Storyboard/IB中有视图控制器容器视图),但这是针对新的应用程序,或者当我决定放弃现有应用程序的2-3年的iOS 5时。 –

与@问题Ben的(否则合理)答案是它只能在一个嵌套层次上工作。除此之外,它会要求每个后续的VC都被定制以将嵌套视图控制器保存在prepareForSegue中。

为了解决这个问题,我花了太多时间去研究一个基于NSObject的索引,你可以添加到Storyboard,绑定到一个场景,然后根据类型和restoreId将它的父VC注册到全局索引中。这可以工作/可以工作,但最终会付出太多的努力,并且仍然需要两个步骤来进行可视绑定,并以编程方式查找。

对于我来说,最简单,最普遍的解决方案是懒洋洋地爬下视图控制器层次

在我简单的测试项目中,添加以下行viewDidLoad中:

self.left.data = [ 
     "Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro.", 
     "De carne lumbering animata corpora quaeritis." ] 

其中left定义为:

lazy var left:CollectionViewController = { [unowned self] in 
    return self.childViewControllerWithId("Left") as! CollectionViewController }() 

childViewControllerWithId定义为:

extension UIViewController { 
    func childViewControllerWithId(rid:String) -> UIViewController? { 

     // check immediate child controllers 
     for vc in self.childViewControllers as! [UIViewController] { 
      if vc.restorationIdentifier == rid { return vc } 
     } 

     // check nested controllers 
     for vc in self.childViewControllers as! [UIViewController] { 
      if let vc = vc.childViewControllerWithId(rid) { 
       return vc 
      } 
     } 

     assert(false, "check your assumptions") 
     return nil 
    } 
} 

请注意,如果需要,您可以根据类型执行其他find变体。另外请注意,上述要求您在Storyboard文件中定义恢复ID。如果你没有重复实例的视图控制器,那么使用类型会更容易。

为了说明什么是希望显而易见的,您不需要执行prepareForSegue,也不必使用延迟加载,您只需致电find(...)即可。