web-dev-qa-db-fra.com

Contrôleur de vue de conteneur d'accès à partir d'iOS parent

sous iOS6, j'ai remarqué la nouvelle vue Conteneur mais je ne sais pas trop comment accéder à son contrôleur à partir de la vue contenant.

Scénario:

example

Je souhaite accéder aux étiquettes dans le contrôleur de vue Alert à partir du contrôleur de vue qui héberge la vue du conteneur.

Il y a une transition entre eux, puis-je l'utiliser?

186
Adam Waite

Oui, vous pouvez utiliser le segue pour accéder au contrôleur de vue enfant (et à sa vue et ses sous-vues). Donnez à la séquence un identifiant (tel que alertview_embed), à l'aide de l'inspecteur Attributs de Storyboard. Ensuite, demandez au contrôleur de vue parent (celui qui héberge la vue conteneur) de mettre en œuvre 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...
   }
}
348
Peter E

Vous pouvez le faire simplement avec self.childViewControllers.lastObject (en supposant que vous n’ayez qu’un enfant, sinon utilisez objectAtIndex:). 

50
rdelmar

pour la programmation rapide

tu peux écrire comme ça

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
    }
}
23
Sruit A.Suk

L’approche prepareForSegue fonctionne, mais elle repose sur la chaîne magique d’identificateur de séquence. Peut-être qu'il y a un meilleur moyen.

Si vous connaissez la classe du VC que vous recherchez, vous pouvez le faire très proprement avec une propriété calculée:

var camperVan: CamperVanViewController? {
  return childViewControllers.flatMap({ $0 as? CamperVanViewController }).first
  // This works because `flatMap` removes nils
}

Cela repose sur childViewControllers. Bien que je sois d’accord, il pourrait être fragile de compter sur le premier, mais nommer la classe que vous recherchez donne l’impression que cette classe est assez solide.

15
SimplGy

Une réponse mise à jour pour Swift 3, utilisant une propriété calculée:

var jobSummaryViewController: JobSummaryViewController {
    get {
        let ctrl = childViewControllers.first(where: { $0 is JobSummaryViewController })
        return ctrl as! JobSummaryViewController
    }
}

Cela ne fait qu'itérer la liste des enfants jusqu'à la première correspondance.

9
Robin Daugherty

self.childViewControllers est plus pertinent lorsque vous avez besoin du contrôle du parent. Par exemple, si le contrôleur enfant est une vue sous forme de table et que vous souhaitez le recharger de force ou modifier une propriété via un clic ou tout autre événement sur le contrôleur de vue parent, vous pouvez le faire en accédant à l'instance de ChildViewController et non via prepareForSegue. Les deux ont leurs applications de différentes manières.

8
Gautam Jain

Si quelqu'un cherche Swift 3.0 ,

viewController1 , viewController2 et ainsi de suite seront alors accessibles.

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
Marco Leong

Avec générique, vous pouvez faire des choses douces. Voici une extension à Array:

extension Array {
    func firstMatchingType<Type>() -> Type? {
        return first(where: { $0 is Type }) as? Type
    }
}

Vous pouvez ensuite le faire dans votre viewController:

var viewControllerInContainer: YourViewControllerClass? {
    return childViewControllers.firstMatchingType()!
}
1
Sunkas

Il existe un autre moyen d'utiliser l'instruction switch de Swift sur le type du 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
Joanna Carter

J'utilise un code comme:

- (IBAction)showCartItems:(id)sender{ 
  ListOfCartItemsViewController *listOfItemsVC=[self.storyboard instantiateViewControllerWithIdentifier:@"ListOfCartItemsViewController"];
  [self addChildViewController:listOfItemsVC];
 }
1
Mannam Brahmam

tu peux écrire comme ça

- (IBAction)showDetail:(UIButton *)sender {  
            DetailViewController *detailVc = [self.childViewControllers firstObject];  
        detailVc.lable.text = sender.titleLabel.text;  
    }  
}
0
Khurshid