IBOutlet link to embedded view controller

前端 未结 4 897
刺人心
刺人心 2021-02-02 07:29

I have a complex iPad view that I manage by having several view controllers. I previously (before iOS6/XCode 4.5) did this by allocating my view controllers in code, and hooked

相关标签:
4条回答
  • 2021-02-02 07:54

    I'm not sure what you mean by "retrieve the embedded controller". When you want to use a controller you use the UIStoryboard method instantiateViewControllerWithIdentifier:, using the identifier that you give to the controller in IB. You can also use the performSegueWithIdentifier:sender: method (which also instantiated the view controller). You should check out the "Using View Controllers in Your App" section in the Apple docs. It also makes reference to the fact that child view controllers are instantiated at the same time as the container controller.

    After edit: If you embed a container view in another view controller, that embedded view's controller can be referenced from the containing controller with self.childViewControllers (which will be an array, so if there is just one, you can get it with lastObject).

    0 讨论(0)
  • 2021-02-02 07:58

    Another option for some cases is to capture the embedded controller using -prepareForSegue:sender:.

    For example, if I have a UINavigationController embedded within a CustomContainerViewController, I can name the embed segue embedContentStack in the storyboard and capture it in 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;
        }
    }
    
    0 讨论(0)
  • 2021-02-02 08:07

    Here is another thread about it: Access Container View Controller from Parent iOS

    They propose to keep a reference in prepareForSegue or search for the embedded viewController in self.childViewControllers

    0 讨论(0)
  • 2021-02-02 08:08

    Note of Caution

    Before proceeding to use an answer to this question, you may wish to reflect whether the embedded things really need to be view controllers.

    Eg, if you're embedding a UICollectionViewController subclass, could you instead embed a UICollectionView subclass? Or, even better, could you embed a UIView subclass that hides away the UICollectionView behind a simple ViewModel?

    In the code base I'm currently working on, I'm embedding two view controllers in to another view controller. Both could fairly easily be plain views instead, and could then be more easily bound to in the storyboard, without this messy code.

    Unfortunately, they are currently view controllers and I'm not in a position to simplify them in to plain views right now, so this will have to do.

    Background

    I'm using the approach of picking up the embed segue in prepare(for segue:, sender:) as suggested by Playful Geek here.

    I wanted to show the swift I'm using for this, as it seems to be fairly tidy…

    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

    I've chosen to name segues as action methods.

    Using an enum cases for segue identifiers means you've got the compiler and tooling on your side, so its much harder to get a segue name wrong.

    Keeping the segue ids in a private enum within the extension scope seems appropriate in this case as these segues are not needed anywhere else (they can't be performed, for example).

    I'm using implicitly unwrapped types for the embedded view controllers because (in my case anyway) it's a logic error if they are missing.

    Similarly, I'm also happy to force cast the destination view controller types. Again, it would be a logic error if these types are not the same.

    0 讨论(0)
提交回复
热议问题