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:
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?
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...
}
}
Vous pouvez le faire simplement avec self.childViewControllers.lastObject
(en supposant que vous n’ayez qu’un enfant, sinon utilisez objectAtIndex:
).
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
}
}
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.
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.
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.
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")
}
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()!
}
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
}
}
J'utilise un code comme:
- (IBAction)showCartItems:(id)sender{
ListOfCartItemsViewController *listOfItemsVC=[self.storyboard instantiateViewControllerWithIdentifier:@"ListOfCartItemsViewController"];
[self addChildViewController:listOfItemsVC];
}
tu peux écrire comme ça
- (IBAction)showDetail:(UIButton *)sender {
DetailViewController *detailVc = [self.childViewControllers firstObject];
detailVc.lable.text = sender.titleLabel.text;
}
}