简体   繁体   中英

How should I access an IBOutlet stored in the view controller holding my container view? (Swift 4)

In my app I want to have multiple container views stored in my main view controller. From there I want to be able to modify the constraints of the container views from both the main view controller and from the container views.

I've made a simple Xcode project and made an example GIF that shows what I want to be able to do.

模拟器GIF

故事板

The "Reset" button is stored in a container view in my main view controller. The container view is centered vertically and horizontally using constraints. The "Up", "Right", "Down", and "Left" buttons modify existing constraints of the container view. I'd like to be able to modify the constraints of the container view using the "Reset" button inside of the container view.

Every time I try to access/modify the constraint IBOutlets stored in the main view controller from within the container view it crashes saying "fatal error: unexpectedly found nil".

What is the best way to achieve this functionality? I'm all ears to your suggestions.

Thanks in advance.

ViewController.swift (main view controller)

class ViewController: UIViewController {
    @IBOutlet weak var ContainerViewVerticalConstraint: NSLayoutConstraint!
    @IBOutlet weak var ContainerViewHorizontalConstraint: NSLayoutConstraint!

    @IBAction func upButtonPressed(_ sender: Any) {
        ContainerViewVerticalConstraint.constant = -100
    }

    @IBAction func rightButtonPressed(_ sender: Any) {
        ContainerViewHorizontalConstraint.constant = 50
    }

    @IBAction func downButtonPressed(_ sender: Any) {
        ContainerViewVerticalConstraint.constant = 100
    }

    @IBAction func leftButtonPressed(_ sender: Any) {
        ContainerViewHorizontalConstraint.constant = -50
    }
}

ContainerViewController.swift (container view)

class ContainerViewController: UIViewController {
    @IBAction func resetButtonPressed(_ sender: Any) {
        // Modify the constraints of the container view when this button is pressed
    }
}

The container view is embedded with an embed segue. You could do the following:

  1. Find the embed segue in the Document Outline and give it an identifier such as "embedResetView" .
  2. In prepareForSegue , pass the two constraints to properties in the destination (Reset) view if segue.identifier is "embedResetView" . The constraints are objects, so they are passed by reference.

     override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "embedResetView" { if let dvc = segue.destination as? ContainerViewController { dvc.horizontalConstraint = ContainerViewHorizontalConstraint dvc.verticalConstraint = ContainerViewVerticalConstraint } } } 
  3. When the reset button is pressed, modify the constant property in those constraints.

     class ContainerViewController: UIViewController { weak var horizontalConstraint: NSLayoutConstraint? weak var verticalConstraint: NSLayoutConstraint? @IBAction func resetButtonPressed(_ sender: Any) { horizontalConstraint?.constant = 0 verticalConstraint?.constant = 0 } } 

You can use a delegate pattern to pass events or data between your view controllers.

First of all, you should create a protocol in your ContainerViewController like that:

protocol ContainerViewControllerDelegate: class {
    func containerControllerDidRequestViewReset()
}

After that, add a delegate property to ContainerViewController:

weak var delegate: ContainerViewControllerDelegate?

At your reset button function call the protocol method like that:

@IBAction func resetButtonPressed(_ sender: Any) {
    // Modify the constraints of the container view when this button is pressed
    delegate?.containerControllerDidRequestViewReset()
}

Than, navigate to your Storyboard file and add an identifier to your segue from ViewController to ContainerViewController, for example "ToContainerViewSegueID". In your main ViewController class implement following method:

func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "ToContainerViewSegueID" {
        if let containerVC = segue.destination as? ContainerViewController {
            containerVC.delegate = self
        }
    }
}

After that, your should implement ContainerViewControllerDelegate into your main ViewController class. For example, you can do this using extension in the same file like that:

class ViewController: UIViewController {
    //your code goes here
}

extension ViewController: ContainerViewControllerDelegate {
    func containerControllerDidRequestViewReset() {
        //here is a good place to reset your constraints values
        ContainerViewVerticalConstraint.constant = 0
        ContainerViewHorizontalConstraint.constant = 0
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM