Search code examples
swiftuilabeluitextviewsegue

Pushing information between segues won't work


I have views A and B.

View A has two different segues to view B, and my prepareForSegue:

override func prepare(for segue: UIStoryboardSegue, sender: Any?)
    {
        let nextView = segue.destination as! LabelWithTextView
        nextView.HeaderLabel = UILabel()
        nextView.TextToDisplay = UITextView()

        if segue.identifier == "segue_to_tc"
        {

            nextView.HeaderLabel.text = "Terms and Conditions"
            nextView.TextToDisplay.text = "Terms and Conditions agreement will be displayed here once available."
        }
        else if segue.identifier == "segue_to_p"
        {
            nextView.HeaderLabel.text = "Privacy Policy"
            nextView.TextToDisplay.text = "Privacy Policy agreement will be displayed here once available."
        }
    }

And View B:

class LabelWithTextView: UIViewController
{
    var HeaderLabel: UILabel!

    var TextToDisplay: UITextView!


    override func viewDidLoad()
    {
        super.viewDidLoad()

        self.navigationController?.setNavigationBarHidden(false, animated: true)
        TextToDisplay.isEditable = false
        self.view.bringSubview(toFront: HeaderLabel)
        self.view.bringSubview(toFront: TextToDisplay)
    }
}

But when I perform the segue , no information is being displayed:

View B after segue

In previous iteration I had two objects in my storyboard with outlets and they did not change either. If I take out the HeaderLabel and TextToDisplay instantiation in PrepareForSegue, it crashes because they are nil.

Is there a way to delete the instantiation in PrepareForSegue ? How can I pass the information correctly ?


Solution

  • The code you included in your question doesn't work because you never added HeaderLabel and TextToDisplay as subviews of self.view in LabelWithTextView.

    Your “previous iteration”, where HeaderLabel and TextToDisplay were in the storyboard, probably didn't work because you were trying to access HeaderLabel and TextToDisplay before they were loaded. When UIKit performs a segue, it instantiates the destination view controller and sends the prepareForSegue:sender: message before it loads the destination view controller's view.

    It is generally not the job of the source view controller to directly access the view hierarchy of the destination view controller.

    One common way to fix this is to introduce a model object and pass that to the destination. For example, we could create a struct to hold the policy details:

    struct PolicyModel {
        var title: String
        var body: String
    }
    

    Then we can give the destination view controller a property of this type, and use the property to configure the views after they're loaded:

    class PolicyViewController: UIViewController {
    
        var policy = PolicyModel(title: "", body: "") {
            didSet { updateViews() }
        }
    
        @IBOutlet var titleLabel: UILabel!
        @IBOutlet var bodyView: UITextView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            updateViews()
        }
    
        private func updateViews() {
            guard isViewLoaded else { return }
            titleLabel.text = policy.title
            bodyView.text = policy.body
        }
    }
    

    Finally, in the segue source, we can set the destination's policy based on the segue identifier:

    class SourceViewController: UIViewController {
    
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            switch (segue.identifier ?? "", segue.destination) {
            case ("TermsAndConditions", let destination as PolicyViewController):
                destination.policy = PolicyModel(title: "Terms and Conditions", body: "Blah blah blah")
            case ("Privacy", let destination as PolicyViewController):
                destination.policy = PolicyModel(title: "Privacy Policy", body: "Blah blah blah")
            default: super.prepare(for: segue, sender: sender)
            }
        }
    
    }