[英]Access Container View Controller from Parent iOS
in iOS6 I noticed the new Container View but am not quite sure how to access it's controller from the containing view.在 iOS6 中,我注意到了新的容器视图,但不太确定如何从包含视图访问它的控制器。
Scenario:设想:
I want to access the labels in Alert view controller from the view controller that houses the container view.我想从包含容器视图的视图控制器访问 Alert 视图控制器中的标签。
There's a segue between them, can I use that?它们之间有一个 segue,我可以使用它吗?
Yes, you can use the segue to get access the child view controller (and its view and subviews).是的,您可以使用 segue 来访问子视图控制器(及其视图和子视图)。 Give the segue an identifier (such as
alertview_embed
), using the Attributes inspector in Storyboard.使用 Storyboard 中的属性检查器为 segue 提供一个标识符(例如
alertview_embed
)。 Then have the parent view controller (the one housing the container view) implement a method like this:然后让父视图控制器(容纳容器视图的控制器)实现如下方法:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSString * segueName = segue.identifier;
if ([segueName isEqualToString: @"alertview_embed"]) {
AlertViewController * childViewController = (AlertViewController *) [segue destinationViewController];
AlertView * alertView = childViewController.view;
// do something with the AlertView's subviews here...
}
}
You can do that simply with self.childViewControllers.lastObject
(assuming you only have one child, otherwise use objectAtIndex:
).您可以简单地使用
self.childViewControllers.lastObject
来做到这一点(假设您只有一个孩子,否则使用objectAtIndex:
)。
for Swift Programming用于 Swift 编程
you can write like this你可以这样写
var containerViewController: ExampleViewController?
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// you can set this name in 'segue.embed' in storyboard
if segue.identifier == "checkinPopupIdentifierInStoryBoard" {
let connectContainerViewController = segue.destinationViewController as ExampleViewController
containerViewController = connectContainerViewController
}
}
The prepareForSegue
approach works, but it relies on the segue identifier magic string. prepareForSegue
方法有效,但它依赖于 segue 标识符魔术字符串。 Maybe there's a better way.也许有更好的方法。
If you know the class of the VC you're after, you can do this very neatly with a computed property:如果你知道你想要的 VC 的类,你可以使用计算属性非常巧妙地做到这一点:
var camperVan: CamperVanViewController? {
return childViewControllers.flatMap({ $0 as? CamperVanViewController }).first
// This works because `flatMap` removes nils
}
This relies on childViewControllers
.这依赖于
childViewControllers
。 While I agree it could be fragile to rely on the first one, naming the class you seek makes this seem quite solid.虽然我同意依赖第一个可能很脆弱,但命名您要查找的类会使它看起来非常可靠。
An updated answer for Swift 3, using a computed property: Swift 3 的更新答案,使用计算属性:
var jobSummaryViewController: JobSummaryViewController {
get {
let ctrl = childViewControllers.first(where: { $0 is JobSummaryViewController })
return ctrl as! JobSummaryViewController
}
}
This only iterates the list of children until it reaches the first match.这只会迭代子列表,直到它到达第一个匹配项。
self.childViewControllers
is more relevant when you need control from the parent. self.childViewControllers
当您需要来自父级的控制时更为相关。 For instance, if the child controller is a table view and you want to reload it forcefully or change a property via a button tap or any other event on Parent View Controller, you can do it by accessing ChildViewController's instance and not via prepareForSegue.例如,如果子控制器是一个表视图,并且您想要强制重新加载它或通过点击按钮或父视图控制器上的任何其他事件更改属性,您可以通过访问 ChildViewController 的实例而不是通过 prepareForSegue 来完成。 Both have their applications in different ways.
两者都有不同的应用。
There is another way using Swift's switch statement on the type of the view controller:还有另一种方法在视图控制器的类型上使用 Swift 的 switch 语句:
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
switch segue.destination
{
case let aViewController as AViewController:
self.aViewController = aViewController
case let bViewController as BViewController:
self.bViewController = bViewController
default:
return
}
}
I use Code like:我使用这样的代码:
- (IBAction)showCartItems:(id)sender{
ListOfCartItemsViewController *listOfItemsVC=[self.storyboard instantiateViewControllerWithIdentifier:@"ListOfCartItemsViewController"];
[self addChildViewController:listOfItemsVC];
}
In case someone is looking for Swift 3.0 ,如果有人正在寻找Swift 3.0 ,
viewController1 , viewController2 and so on will then be accessible.然后可以访问viewController1 、 viewController2等等。
let viewController1 : OneViewController!
let viewController2 : TwoViewController!
// Safety handling of optional String
if let identifier: String = segue.identifier {
switch identifier {
case "segueName1":
viewController1 = segue.destination as! OneViewController
break
case "segueName2":
viewController2 = segue.destination as! TwoViewController
break
// ... More cases can be inserted here ...
default:
// A new segue is added in the storyboard but not yet including in this switch
print("A case missing for segue identifier: \(identifier)")
break
}
} else {
// Either the segue or the identifier is inaccessible
print("WARNING: identifier in segue is not accessible")
}
With generic you can do some sweet things.使用 generic 你可以做一些甜蜜的事情。 Here is an extension to Array:
这是数组的扩展:
extension Array {
func firstMatchingType<Type>() -> Type? {
return first(where: { $0 is Type }) as? Type
}
}
You can then do this in your viewController:然后,您可以在 viewController 中执行此操作:
var viewControllerInContainer: YourViewControllerClass? {
return childViewControllers.firstMatchingType()!
}
you can write like this你可以这样写
- (IBAction)showDetail:(UIButton *)sender {
DetailViewController *detailVc = [self.childViewControllers firstObject];
detailVc.lable.text = sender.titleLabel.text;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.