ios 将子视图控制器链接到故事板中的父视图控制器
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8198698/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Linking child view controllers to a parent view controller within storyboard
提问by Constantino Tsarouhas
Can you associate child view controllers to a custom container view controller in Storyboard?
您可以将子视图控制器与 Storyboard 中的自定义容器视图控制器相关联吗?
I can link child view controllers to a tab view controller, and I can link one view controller to a navigation controller.
我可以将子视图控制器链接到选项卡视图控制器,也可以将一个视图控制器链接到导航控制器。
What must I do to the container VC to accept child VCs?
我必须对容器 VC 做什么才能接受子 VC?
回答by Ben Mosher
As something of a combo of Caleb and Matt's answers, I did:
作为 Caleb 和 Matt 答案的组合,我做了:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:@"cpdc_check_embed"]) {
self.checkVC = segue.destinationViewController;
}
}
...where checkVC
is a property on the container controller:
...checkVC
容器控制器上的属性在哪里:
@property (weak,nonatomic) PXPCheckViewController * checkVC;
You just have to set your embed
segue's Storyboard ID
to whatever you want (in this case, cpdc_check_embed
):
您只需将embed
segue设置Storyboard ID
为您想要的任何内容(在本例中为cpdc_check_embed
):
...and then check the identifier in -prepareForSegue:sender:
.
...然后检查中的标识符-prepareForSegue:sender:
。
Still not an outlet, but cleaner than Matt's (IMHO) and more specific than Caleb's, and you still get a nice-looking storyboard:
仍然不是出口,但比马特(恕我直言)更干净,比 Caleb 更具体,你仍然会得到一个漂亮的故事板:
回答by Matt
The storyboard deals with built-in container view controllers very nicely, displaying segues to child/root view controllers so that relationships are clearly shown. It is also nice how the children and parent view controllers are separated into different scenes.
故事板很好地处理内置容器视图控制器,显示子/根视图控制器的转场,以便清楚地显示关系。子视图控制器和父视图控制器如何分离到不同的场景中也很好。
If you want to achieve this effect in your own project, then there is a trick that is not perfect but very straightforward. In my example, suppose I have a container view controller that acts like a tab bar controller with only two tabs, 'left' and 'right'. I want to have a scene represent the parent view controller, and two separate scenes represent both the 'left' child view controller and the 'right' child view controller.
如果你想在你自己的项目中实现这种效果,那么有一个技巧并不完美但很直接。在我的示例中,假设我有一个容器视图控制器,它就像一个标签栏控制器,只有两个标签,“左”和“右”。我想要一个场景代表父视图控制器,两个单独的场景代表“左”子视图控制器和“右”子视图控制器。
Even though it is impossible, it would be nice if I could create IBOutlet
s from the container view controller to its children in different scenes, and then when my container view controller is displayed set up the parent/child relationships according to the rules described the UIViewController documentation. If we had references to our 'left' and 'right' child view controllers, then we could set up the relationships no problem.
即使这是不可能的,如果我可以IBOutlet
在不同场景中从容器视图控制器到其子项创建s,然后当我的容器视图控制器显示时根据UIViewController描述的规则设置父/子关系就好了文档。如果我们引用了我们的“左”和“右”子视图控制器,那么我们可以毫无问题地建立关系。
The standard solution to this referencing problem is to create references to child view controllers by dragging in Object
outlets into the container view controller's scene, and then specifying their class type as being instances of the child view controller classes.
这个引用问题的标准解决方案是通过将Object
出口拖入容器视图控制器的场景中来创建对子视图控制器的引用,然后将它们的类类型指定为子视图控制器类的实例。
In order to keep children separated in different scenes like Apple's built-in containers, however, we will use a different trick. First, suppose we have the following properties declared in our container class, ContainerViewController
:
然而,为了让孩子们像苹果内置的容器一样在不同的场景中保持分离,我们将使用不同的技巧。首先,假设我们在容器类中声明了以下属性ContainerViewController
:
@property (nonatomic, strong, readwrite) UIViewController *leftViewController;
@property (nonatomic, strong, readwrite) UIViewController *rightViewController;
In our storyboard, select the scene representing the 'left' view controller. In the attributes inspector, set the view controller's identifier
property to "cvc_leftViewController"
("cvc_" refers to ContainerViewController
, but really the identifier can be anything you want). Do the same for the right view controller's scene, setting it's identifier to "cvc_rightViewController"
.
在我们的故事板中,选择代表“左”视图控制器的场景。在属性检查器中,将视图控制器的identifier
属性设置为"cvc_leftViewController"
(“cvc_”指的是ContainerViewController
,但实际上标识符可以是您想要的任何内容)。对右视图控制器的场景执行相同操作,将其标识符设置为"cvc_rightViewController"
。
Now insert the following code into ContainerViewController
's viewDidLoad
method:
现在将以下代码插入到ContainerViewController
的viewDidLoad
方法中:
if (self.storyboard) {
_leftViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"cvc_leftViewController"];
_rightViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"cvc_rightViewController"];
}
When ContainerViewController
is loaded from the storyboard, it will go grab the 'left' and 'right' view controllers from their respective scenes and set references to them via its properties. Now that you have control of the child view controller instances, you can set up the parent/child relationships however you like. To learn how to do that properly refer to the UIViewController documentation.
当ContainerViewController
从故事板加载时,它将从各自的场景中获取“左”和“右”视图控制器,并通过其属性设置对它们的引用。现在您可以控制子视图控制器实例,您可以随意设置父/子关系。要了解如何正确执行此操作,请参阅UIViewController 文档。
This trick is not perfect, and has many caveats, but if you are careful you can make it work nicely for your project.
这个技巧并不完美,有很多注意事项,但如果你小心,你可以让它很好地为你的项目工作。
Edit: Although this is completely unnecessary and doesn't mean anything, if you really reallywant to have the storyboard display connections from your container to your child view controllers just like Apple's built-in containers, just use my method above and then set up segues directly between the container scene to the child scenes, and simply never perform those segues. Now everything will work correctly and look pretty too.
编辑:尽管这是完全不必要的,并不意味着什么,如果你真的真的希望有孩子的视图控制器,就像苹果公司的从你的容器故事板显示连接内置容器中,只是用我上面的方法,然后设置直接在容器场景和子场景之间进行转场,并且永远不要执行这些转场。现在一切都将正常工作并且看起来也很漂亮。
回答by Caleb
Can you associate child view controllers to a custom container view controller in Storyboard?
您可以将子视图控制器与 Storyboard 中的自定义容器视图控制器相关联吗?
I think what you're asking here is how to connect a view controller in one scene to an outlet of a view controller in a different scene. I don't believe that's possible, perhaps because the storyboard machinery may not have all the scenes in a storyboard loaded at the same time.
我想你在这里问的是如何将一个场景中的视图控制器连接到不同场景中视图控制器的出口。我不相信这是可能的,也许是因为故事板机器可能不会同时加载故事板中的所有场景。
You're probably asking this because you want to pass some information from one view controller to another as you segue from one scene to the next. The way to do this when you're working with storyboards is to override -prepareForSegue:sender:
in one or both view controllers affected by the segue. The UIStoryboardSegue object provided in the segue
parameter has sourceViewController
and destinationViewController
properties, and also an identifier
property. You can use these properties to identify the segue that's about to transfer data between the view controllers.
您可能会问这个问题,因为当您从一个场景切换到下一个场景时,您想将一些信息从一个视图控制器传递到另一个视图控制器。当您使用故事板时,执行此操作的方法是-prepareForSegue:sender:
在受转场影响的一个或两个视图控制器中进行覆盖。segue
参数中提供的 UIStoryboardSegue 对象有sourceViewController
和destinationViewController
属性,也是一个identifier
属性。您可以使用这些属性来识别即将在视图控制器之间传输数据的 segue。
Ray Wenderlich's blog has a nice two-part tutorial on using storyboards that may help you:
Ray Wenderlich 的博客有一个很好的关于使用故事板的两部分教程,可以帮助您:
Part 1covers setting up a storyboard project, adding scenes, and creating segues.
Part 2deals with using segues to transition between scenes, including the
prepareForSeque
method mentioned above.
iOS 5 allows multiple view controllers to be active in the same scene (although one should still be in charge), so a single scene in your storyboard might have several controllers. You can use outlets to connect these controllers to each other, and you can configure those connections the same way you did in IB: control-drag from one controller to another in the same scene. The usual outlet list will pop open to let you choose which outlet to connect.
iOS 5 允许多个视图控制器在同一个场景中处于活动状态(尽管仍然应该由一个人负责),因此故事板中的单个场景可能有多个控制器。您可以使用插座将这些控制器相互连接起来,并且您可以像在 IB 中所做的那样配置这些连接:在同一场景中从一个控制器控制拖动到另一个控制器。通常的插座列表将弹出,让您选择要连接的插座。
回答by Matt__C
The key to using multiple controllers in one scene (what I believe you are after here) is using the mysterious Object from the Objects list in IB to represent the other view controller and hooking up its outlets.
在一个场景中使用多个控制器的关键(我相信你在这里追求的)是使用 IB 中对象列表中的神秘对象来表示另一个视图控制器并连接它的出口。
This answer How to create custom view controller container using storyboard in iOS 5should help I hope. The answer also provides a working example app which is very helpful.
我希望这个答案How to create custom view controller container using storyboard in iOS 5应该会有所帮助。答案还提供了一个非常有用的工作示例应用程序。
回答by Chris Conover
The problem with @Ben's (otherwise reasonable) answer is that it only works at one level of nesting. Beyond that, it would required that every subsequent VC is customized to save the nesting view controller in prepareForSegue.
@Ben 的(其他合理的)答案的问题在于它仅适用于一层嵌套。除此之外,还需要自定义每个后续 VC 以在 prepareForSegue 中保存嵌套视图控制器。
To solve this, I spent too much time exploring an NSObject based index that that you could add to the Storyboard, bind to a scene, and which would then register it's parent VC in a global index, based on type and restorationId. That works / can work, but is too much effort in the end, and still requires the two step process of visually binding, and programmatically looking up.
为了解决这个问题,我花了太多时间探索基于 NSObject 的索引,您可以将其添加到 Storyboard,绑定到场景,然后根据类型和恢复 ID 在全局索引中注册它的父 VC。行得通/能行,但到头来太费力了,还需要视觉绑定和程序化查找两步过程。
For me, the simplest and most general solution is to lazily descend the view controller hierarchy
对我来说,最简单和最通用的解决方案是懒惰地降低视图控制器层次结构
In my simple test project, I added the following lines to viewDidLoad:
在我的简单测试项目中,我在 viewDidLoad 中添加了以下几行:
self.left.data = [
"Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro.",
"De carne lumbering animata corpora quaeritis." ]
where left
is defined as:
其中left
定义为:
lazy var left:CollectionViewController = { [unowned self] in
return self.childViewControllerWithId("Left") as! CollectionViewController }()
and childViewControllerWithId
is defined as:
并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
}
}
Note that you could do other find
variants based on type, if need be. Also note that the above requires that you define the restoration id in the Storyboard file. If you did not have repeated instances of the same view controller, then using type would be easier.
请注意find
,如果需要,您可以根据类型进行其他变体。另请注意,以上要求您在 Storyboard 文件中定义恢复 ID。如果您没有相同视图控制器的重复实例,那么使用类型会更容易。
And to state what is hopefully obvious, you don't need to implement prepareForSegue, nor do you have to use the lazy loading, you just have to call find(...)
.
并且要说明什么是显而易见的,您不需要实现 prepareForSegue,也不需要使用延迟加载,您只需要调用find(...)
.