web-dev-qa-db-fra.com

Lien IBOutlet vers le contrôleur de vue intégré

J'ai une vue iPad complexe que je gère en ayant plusieurs contrôleurs de vue. Je l'avais déjà fait (avant iOS6/XCode 4.5) en allouant mes contrôleurs de vue en code et en leur connectant les différentes vues via des liens vers la vue principale. 

Ce que je voudrais faire est d'utiliser les nouvelles vues de conteneur pour incorporer les contrôleurs de vue dans le fichier de storyboard. Je ne semble pas pouvoir établir de lien IBOutlet avec le contrôleur de vue intégré vers le contrôleur principal. 

Est-il possible de faire cela? Ou pour récupérer le contrôleur intégré via une balise ou quelque chose dans le code?

Cette question concerne spécifiquement l'utilisation des vues de conteneur

34
Dan F

Je ne suis pas sûr de ce que vous entendez par "récupérer le contrôleur intégré". Lorsque vous souhaitez utiliser un contrôleur, vous utilisez la méthode UIStoryboard instantiateViewControllerWithIdentifier :, à l'aide de l'identifiant que vous avez attribué au contrôleur dans IB. Vous pouvez également utiliser la méthode performSegueWithIdentifier: sender: (qui instancia également le contrôleur de vue). Vous devriez consulter la section "Utilisation des contrôleurs de vue dans votre application" dans la documentation Apple. Il fait également référence au fait que les contrôleurs de vue enfant sont instanciés en même temps que le contrôleur de conteneur.

Après édition: si vous incorporez une vue conteneur dans un autre contrôleur de vue, le contrôleur de cette vue intégrée peut être référencé à partir du contrôleur conteneur avec self.childViewControllers (qui sera un tableau, ainsi s'il n'y en a qu'un, vous pouvez l'obtenir avec lastObject) .

21
rdelmar

Une autre option dans certains cas consiste à capturer le contrôleur intégré à l'aide de -prepareForSegue:sender:.

Par exemple, si j'ai une UINavigationController intégrée à une CustomContainerViewController, je peux nommer la séquence intégrée embedContentStack dans le storyboard et la capturer dans CustomContainerViewController via

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"embedContentStack"]) {
        // can't assign the view controller from an embed segue via the storyboard, so capture here
        _contentStack = (UINavigationController *)segue.destinationViewController;
    }
}
66
PlayfulGeek

Voici un autre fil à ce sujet: Contrôleur de la vue du conteneur d’accès depuis le parent iOS

Ils proposent de conserver une référence dans prepareForSegue ou de rechercher le viewController intégré dans self.childViewControllers

2
theguy

Note de prudence

Avant d’utiliser une réponse à cette question, vous voudrez peut-être déterminer si les éléments incorporés doivent réellement être des contrôleurs de vue. 

Par exemple, si vous intégrez une sous-classe UICollectionViewController, pourriez-vous plutôt intégrer une sous-classe UICollectionView? Ou, mieux encore, pourriez-vous intégrer une sous-classe UIView qui cache la UICollectionView derrière un simple ViewModel?

Dans la base de code sur laquelle je travaille actuellement, j'intègre deux contrôleurs de vue dans un autre contrôleur de vue. Les deux pourraient assez facilement être des vues simples à la place, et pourraient alors être plus facilement liés au storyboard, sans ce code désordonné. 

Malheureusement, ils sont actuellement des contrôleurs de vues et je ne suis pas en mesure de les simplifier pour les vues simples pour le moment, donc cela devra être fait.

Contexte

J'utilise l'approche consistant à prendre la séquence intégrée dans prepare(for segue:, sender:) comme suggéré par Geful Playful ici.

Je voulais montrer le Swift que j'utilise pour cela, car il semble être assez bien rangé…

class EditionLandingViewController: UIViewController {
    fileprivate var titlesView: SectionTitlesViewController!
    fileprivate var sectionsView: SectionsViewController!
}

//MARK:-

extension EditionLandingViewController {
    private enum SegueId: String {
        case embedTitles
        case embedSections
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        super.prepare(for: segue, sender: sender)

        guard
            let segueRawId = segue.identifier,
            let segueId = SegueId(rawValue: segueRawId)
            else { return }

        switch segueId {
        case .embedTitles:
            self.titlesView = segue.destination as! SectionTitlesViewController

        case .embedSections:
            self.sectionsView = segue.destination as! SectionsViewController
        }
    }
}

Discussion

J'ai choisi de nommer les segues comme méthodes d'action

L'utilisation d'un cas enum pour les identificateurs de division signifie que vous avez le compilateur et les outils de votre côté, il est donc beaucoup plus difficile d'obtenir un nom de division erroné.

Conserver les identifiants de séquence dans un private enum dans la portée de extension semble approprié dans ce cas, car ils ne sont utilisés nulle part ailleurs (ils ne peuvent pas être performed, par exemple).

J'utilise des types implicitement non encapsulés pour les contrôleurs de vue intégrés car (dans mon cas en tout cas), c'est une erreur de logique s'ils sont manquants. 

De même, je suis également heureux de forcer le transfert des types de contrôleur de vue de destination. Encore une fois, ce serait une erreur de logique si ces types ne sont pas identiques.

0
Benjohn