web-dev-qa-db-fra.com

À partir d'un contrôleur de vue dans une vue de conteneur, comment accédez-vous au contrôleur de vue contenant le conteneur?

C'est délicat pour Word mais j'ai un contrôleur de vue (vc1) qui contient une vue de conteneur (j'utilise des storyboards). Dans cette vue de conteneur se trouve un contrôleur de navigation et un contrôleur de vue racine (vc2).

Depuis le vc2, comment puis-je accéder à vc1?

Ou, comment passer de vc1 à vc2? (sans oublier que j'utilise des story-boards).

51
Mark Bridges

Vous pouvez utiliser la méthode prepareForSegue dans Vc1 car une séquence d'intégration se produit lorsque le ContainerViewController devient un enfant. vous pouvez vous passer en tant qu'obj ou stocker une référence à l'enfant pour une utilisation ultérieure.

- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    NSString * segueName = segue.identifier;
    if ([segueName isEqualToString: @"embedseg"]) {
        UINavigationController * navViewController = (UINavigationController *) [segue destinationViewController];
        Vc2 *detail=[navViewController viewControllers][0];
        Vc2.parentController=self;
    }
}

Modifier: correction de code mineur

51
Bonnie

Pour accéder au contrôleur de vue parent à partir de votre contrôleur de vue enfant, vous devez remplacer didMoveToParentViewController:

- (void)didMoveToParentViewController:(UIViewController *)parent {
    [super didMoveToParentViewController:parent];

    //Use parent
}

Sur la commande Xcode + cliquez sur cette méthode pour plus d'informations:

Ces deux méthodes sont publiques pour les sous-classes de conteneurs à appeler lors de la transition entre les contrôleurs enfants. S'ils sont remplacés, les remplacements doivent garantir d'appeler le super. L'argument parent dans ces deux méthodes est nul lorsqu'un enfant est retiré de son parent; sinon, il est égal au nouveau contrôleur de vue parent.

addChildViewController: appellera [enfant willMoveToParentViewController: self] avant d'ajouter l'enfant. Cependant, il n'appellera pas didMoveToParentViewController :. Il est prévu qu'une sous-classe de contrôleur de vue de conteneur effectue cet appel une fois la transition vers le nouvel enfant terminée ou, en cas d'absence de transition, immédiatement après l'appel à addChildViewController :. De même removeFromParentViewController: n'appelle pas [self willMoveToParentViewController: nil] avant de supprimer l'enfant. C'est également la responsabilité de la sous-classe des conteneurs. Les sous-classes de conteneur définissent généralement une méthode qui passe à un nouvel enfant en appelant d'abord addChildViewController:, puis en exécutant une transition qui ajoutera la vue du nouvel enfant dans la hiérarchie de vue de son parent, et enfin appellera didMoveToParentViewController :. De même, les sous-classes définissent généralement une méthode qui supprime un enfant de la manière inverse en appelant d'abord [child willMoveToParentViewController: nil].

17
Firula

Utilisez la propriété parentViewController comme self.parentViewController

10
Borzh

Vous pouvez utiliser la délégation en utilisant la même méthode que Bonnie a utilisée. Voici comment procéder:

Dans votre containerViews ViewController:

class ContainerViewViewController: UIViewController {
   //viewDidLoad and other methods

   var delegate: ContainerViewControllerProtocol?

   @IBAction func someButtonTouched(sender: AnyObject) { 
    self.delegate?.someDelegateMethod() //call this anywhere
   }

}

protocol ContainerViewControllerProtocol {
    func someDelegateMethod()
}

Dans votre ViewController parent:

class ParentViewController: UIViewController, ContainerViewControllerProtocol {
   //viewDidLoad and other methods

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "filterEmbedSegue" {
            let containerViewViewController = segue.destinationViewController as ContainerViewViewController

            containerViewViewController.delegate = self
        }
    }

    func someDelegateMethod() {
        //do your thing
    }
}
10
osrl

Merci Bonnie de m'avoir dit quoi faire. En effet, la méthode de préparation à la séquence est la voie à suivre.

Je clarifie simplement le code et les étapes ici.

Donc, tout d'abord, nommez la séquence (lien) dans le storyboard qui connecte la vue conteneur à son premier contrôleur de vue. J'ai nommé le mien "toContainer".

Ensuite, dans le contrôleur de vue contenant la vue conteneur, ajoutez cette méthode

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString: @"toContainer"]) {
        UINavigationController *navViewController = (UINavigationController *) [segue destinationViewController];
        UIViewController *vc2 = [navViewController viewControllers][0];
    }
}

Donc, vc2 était le contrôleur auquel je voulais obtenir une référence.

Cela a fonctionné pour moi, votre méthode serait légèrement différente à l'intérieur de prepareForSegue si votre premier viewconroller n'était pas un contrôleur de navigation.

2
Mark Bridges

1) sur VC2 exposer une propriété pour passer une référence à VC1

//VC2.h
#import "VC1.h"

@interface VC2 : NSObject
@property (strong, nonatomic) VC1 *parent;
@end

2) sur VC1, passez self dans la propriété exposée dans VC2 dans votre méthode prepareForSegue après avoir configuré l'identifiant de votre séquence sur "ToVC2". Passez ensuite la référence comme ceci:

//VC1.m
@implementation VC1 
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([segue.identifier isEqualToString:@"ToVC2"]) {
    VC2 *vc2 = segue.destinationViewController;
    vc2.parent = self;
}
}
1
smileBot

Swift - Une alternative consiste à créer une référence dans le parent UIViewController (vc1) vers l'enfant/sous-vue UIViewController (vc2) et dans vc2 vers vc1. Attribuez les références dans l'exemple parent (vc1) viewDidLoad () ci-dessous.

Parent UIViewController vc1:

      class vc1: UIViewController {

          @IBOutlet weak var parentLabel: UILabel!
          var childVc2: vc2?;

           overide func viewDidLoad() {
               super.viewDidLoad();
               // Use childViewControllers[0] without type/class verification only 
               // when adding a single child UIViewController 
               childVc2 = self.childViewControllers[0] as? vc2;
               childVc2?.parentVc1 = self
           }
      }

Child UIViewController vc2:

      class vc2: UIViewCortoller {
          var parentVc1: vc1?;

          // At this point child and parent UIViewControllers are loaded and 
          // child views can be accessed
          override func viewWillAppear(_ animated: Bool) {
             parentVc1?.parentLabel.text = "Parent label can be edited from child";
          }
      } 

Dans le Storyboard, n'oubliez pas de définir dans Identity Inspector la classe UIViewContoller parent sur vc1 et la classe UIViewContoller enfant sur vc2. Ctrl + faites glisser de la vue Conteneur dans vc1 UIViewController vers vc2 UIViewController et sélectionnez Intégrer.

0
Matt