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:

example

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?

181
demandé sur Sruit A.Suk 2012-11-08 02:07:28

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...
   }
}
341
répondu Peter E 2012-11-07 22:56:10

vous pouvez faire cela simplement avec self.childViewControllers.lastObject (en supposant que vous n'avez qu'un enfant, sinon utilisez objectAtIndex: ).

49
répondu rdelmar 2013-11-12 15:28:56

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
    }
}
19
répondu Sruit A.Suk 2016-04-17 15:00:02

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.

13
répondu SimplGy 2016-05-20 18:44:52

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.

9
répondu Robin Daugherty 2016-10-16 02:22:50

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.

8
répondu Gautam Jain 2014-10-05 09:10:25

J'utilise le Code comme:

- (IBAction)showCartItems:(id)sender{ 
  ListOfCartItemsViewController *listOfItemsVC=[self.storyboard instantiateViewControllerWithIdentifier:@"ListOfCartItemsViewController"];
  [self addChildViewController:listOfItemsVC];
 }
1
répondu Mannam Brahmam 2016-05-18 11:01:09

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")
}
1
répondu Marco Leong 2016-11-25 01:19:11

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
  }
}
1
répondu Joanna Carter 2016-12-30 12:16:29

vous pouvez écrire comme ceci

- (IBAction)showDetail:(UIButton *)sender {  
            DetailViewController *detailVc = [self.childViewControllers firstObject];  
        detailVc.lable.text = sender.titleLabel.text;  
    }  
}
0
répondu Khurshid 2016-08-17 11:41:26

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()!
}
0
répondu Sunkas 2018-04-24 12:20:17