Will Titus
Will Titus

Reputation: 87

Xcode 8/Swift 3: how to make ViewController save state when segue occurs?

App has two View Controllers: ViewController (this is the main View Controller that displays the majority of the app's content) and SecondViewController (accessible via a UIButton on ViewController; SecondViewController is only used to display a user's inventory, and a UIButton within SecondViewController allows the user to return to the original view, ViewController). Currently, the app uses the "Show" action segue to switch between View Controllers when the user presses the appropriate UIButton. However, after switching from ViewController to SecondViewController, and then pressing the UIButton to return to ViewController, the properties of ViewController have been reverted to the properties that occur when the app launches (background color is changed, certain text fields appear that shouldn't).

So, how do I "save the state" of ViewController when the user moves to SecondViewController, so that the user resumes where they left off when they return to ViewController?

Upvotes: 2

Views: 1265

Answers (3)

K.K.
K.K.

Reputation: 117

Here is a simple example of segue and unwind that you can adapt to your problem... Assume that you have ViewController with label and a button and a SecondViewController with label and a button.

For the first ViewController...

import UIKit

//steps to receive data back from SecondViewController...
//1. create protocol in the SecondViewController (see SecondViewController code)
//2. conform to the protocol

class ViewController: UIViewController, UnwindSegue {

    //3. method that gets triggred.
    func dataReceived(dataSegued: String) {
        labelOne.text = dataSegued
    }

    @IBOutlet weak var textField: UITextField!
    @IBOutlet weak var labelOne: UILabel!

    var textReceived : String = ""

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.

    }

    @IBAction func btPressed(_ sender: Any) {
        performSegue(withIdentifier: "goToSecondController", sender: self)

    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "goToSecondController" {

            let destinationVC = segue.destination as! SecondViewController
            destinationVC.textSegued = textField.text!


            //4. create delegate in the SecondViewController (see SecondViewController code)
            //5. set ourselves up as delegate of SecondViewController
            destinationVC.delegate = self

            //6. then dismiss the SecondViewController (see SecondViewController code)

        }
    }
}

Then for your SecondViewController...

import UIKit

//1. create protocols and delegates to transfer data back
protocol UnwindSegue {
    //single required method with a single parameter
    func dataReceived(data:String)

}

class SecondViewController: UIViewController {

    var textSegued : String?

    //4. create delegate of the protocol of type CanReceive that can be a nil. If it is nil, it doesn't go anywhere when BT is pressed
    var delegate : UnwindSegue?

    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var secondTextField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        label.text = textSegued
    }

    @IBAction func btTwoPressed(_ sender: Any) {

        //this is not triggered if var delegate is nil (as defined as optional)
        delegate?.dataReceived(data: secondTextField.text!)

        //6. dismiss the 2nd VC so you can see the fist VC
        dismiss(animated: true, completion: nil)

    } 

}

Upvotes: 0

Dan Karbayev
Dan Karbayev

Reputation: 2930

What you are looking for is an unwind segue. Here's the simplest way of how to create it:

  1. In your ViewController (or, basically any other view controller you are willing to pop to) create an IBAction that accepts an instance of a segue (function name doesn't really matter):

    @IBAction func unwindToThisVC(segue: UIStoryboardSegue) { }

  2. In the storyboard, go to SecondViewController, and control + drag from your UIButton to the Exit outlet of ViewController and then select the IBAction you've created in step 1: Control+Drag enter image description here

More on Unwind Segues

Upvotes: 2

Lou Franco
Lou Franco

Reputation: 89232

The way you are doing it now (using Show from the second to get back to the first) actually brings up a third VC.

What you want to do is dismiss the second view controller.

The normal way is to implement a protocol for the second one that the first one implements and then to have a function in that protocol for the second one to let the first one know it is done.

When the function is called, the first one dismisses the second and then it will be shown again with its state intact.

Upvotes: 0

Related Questions