问题
in iOS6 I noticed the new Container View but am not quite sure how to access it\'s controller from the containing view.
Scenario:
I want to access the labels in Alert view controller from the view controller that houses the container view.
There\'s a segue between them, can I use that?
回答1:
Yes, you can use the segue to get access the child view controller (and its view and subviews). Give the segue an identifier (such as alertview_embed
), using the Attributes inspector in Storyboard. 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...
}
}
回答2:
You can do that simply with self.childViewControllers.lastObject
(assuming you only have one child, otherwise use objectAtIndex:
).
回答3:
for Swift Programming
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
}
}
回答4:
The prepareForSegue
approach works, but it relies on the segue identifier magic string. 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:
var camperVan: CamperVanViewController? {
return childViewControllers.flatMap({ $0 as? CamperVanViewController }).first
// This works because `flatMap` removes nils
}
This relies on childViewControllers
. While I agree it could be fragile to rely on the first one, naming the class you seek makes this seem quite solid.
回答5:
An updated answer for Swift 3, using a computed property:
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.
回答6:
self.childViewControllers
is more relevant when you need control from the parent. 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. Both have their applications in different ways.
回答7:
There is another way using Swift's switch statement on the type of the view controller :
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
}
}
回答8:
I use Code like:
- (IBAction)showCartItems:(id)sender{
ListOfCartItemsViewController *listOfItemsVC=[self.storyboard instantiateViewControllerWithIdentifier:@"ListOfCartItemsViewController"];
[self addChildViewController:listOfItemsVC];
}
回答9:
In case someone is looking for Swift 3.0,
viewController1, viewController2 and so on will then be accessible.
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")
}
回答10:
With generic you can do some sweet things. 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:
var viewControllerInContainer: YourViewControllerClass? {
return childViewControllers.firstMatchingType()!
}
回答11:
you can write like this
- (IBAction)showDetail:(UIButton *)sender {
DetailViewController *detailVc = [self.childViewControllers firstObject];
detailVc.lable.text = sender.titleLabel.text;
}
}
来源:https://stackoverflow.com/questions/13279105/access-container-view-controller-from-parent-ios