Contrôleur de vue de conteneur d'accès par iOS Parent
dans iOS6 j'ai remarqué la nouvelle vue conteneur mais je ne suis pas sûr de savoir comment accéder à son contrôleur depuis la vue contenant.
scénario:
je veux accéder aux étiquettes dans le contrôleur de vue Alert à partir du contrôleur de vue qui héberge la vue de conteneur.
il y a une séquence entre eux, puis-je utiliser ça?
11 réponses
Oui, vous pouvez utiliser le segue pour accéder au contrôleur de la vue enfant (et sa vue et ses sous-vues). Donnez à la séquence un identificateur (tel que alertview_embed
), en utilisant les attributs inspector dans Storyboard. Ensuite, le contrôleur de vue parent (celui qui héberge la vue du conteneur) implémente une méthode comme celle-ci:
- (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...
}
}
vous pouvez faire cela simplement avec self.childViewControllers.lastObject
(en supposant que vous n'avez qu'un enfant, sinon utilisez objectAtIndex:
).
pour la programmation Swift
vous pouvez écrire comme ceci
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
}
}
l'approche prepareForSegue
fonctionne, mais elle s'appuie sur la chaîne magique de l'Identificateur de séquence. Peut-être il ya une meilleure façon.
si vous connaissez la classe de la CV que vous recherchez, vous pouvez le faire avec une propriété calculée:
var camperVan: CamperVanViewController? {
return childViewControllers.flatMap({ "151900920" as? CamperVanViewController }).first
// This works because `flatMap` removes nils
}
cela dépend de childViewControllers
. Bien que je sois d'accord qu'il pourrait être fragile de compter sur le premier, nommer la classe que vous recherchez fait que cela semble assez solide.
une réponse mise à jour pour Swift 3, en utilisant une propriété calculée:
var jobSummaryViewController: JobSummaryViewController {
get {
let ctrl = childViewControllers.first(where: { "151900920" is JobSummaryViewController })
return ctrl as! JobSummaryViewController
}
}
cela ne fait que répéter la liste des enfants jusqu'à ce qu'elle atteigne le premier match.
self.childViewControllers
est plus pertinent lorsque vous avez besoin de contrôle de la part du parent. Par exemple, si le contrôleur enfant est une vue de table et que vous souhaitez le recharger avec force ou modifier une propriété via un bouton ou tout autre événement sur le contrôleur de vue Parent, vous pouvez le faire en accédant à L'instance du contrôleur ChildViewController et non via prepareForSegue. Les deux ont des applications différentes.
J'utilise le Code comme:
- (IBAction)showCartItems:(id)sender{
ListOfCartItemsViewController *listOfItemsVC=[self.storyboard instantiateViewControllerWithIdentifier:@"ListOfCartItemsViewController"];
[self addChildViewController:listOfItemsVC];
}
dans le cas où quelqu'un cherche Swift 3.0 ,
viewController1 , viewController2 et ainsi de suite sera alors 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")
}
il y a une autre façon d'utiliser L'instruction switch de Swift sur le type de contrôleur de vue:
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
}
}
vous pouvez écrire comme ceci
- (IBAction)showDetail:(UIButton *)sender {
DetailViewController *detailVc = [self.childViewControllers firstObject];
detailVc.lable.text = sender.titleLabel.text;
}
}
avec generic vous pouvez faire des choses douces. Voici une extension à Array:
extension Array {
func firstMatchingType<Type>() -> Type? {
return first(where: { "151900920" is Type }) as? Type
}
}
vous pouvez alors le faire dans votre viewController:
var viewControllerInContainer: YourViewControllerClass? {
return childViewControllers.firstMatchingType()!
}