Sending data with Segue with Swift

I have two view controllers and two views. In my first view, I set the variable 'currentUser' to false. I need to be able to set 'currentUser' to true in the second view controller.

When trying to reference 'currentUser' from the second view it's not picking it up as 'currentUser' is defined in the first view controller.

How do I carry across variables with segue?


Set values from Any ViewController to a Second One using segues

Like this:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

    if(segue.identifier == "yourIdentifierInStoryboard") {

        let yourNextViewController = (segue.destinationViewController as yourNextViewControllerClass)
        yourNextViewController.value = yourValue

And in your yourNextViewController class.

class yourNextViewControllerClass {

    var value:Int! // or whatever

You can call this also programmatically:

 self.performSegueWithIdentifier("yourIdentifierInStoryboard", sender: self)

Set values from your DestinationViewController back to your Primary (First) ViewController

1. Implement a protocol, for example create a file called protocol.swift.

    protocol changeUserValueDelegate {
       func changeUser(toValue:Bool)
    }

2. set the delegate on your second View

    class yourNextViewControllerClass {

    var delegate:changeUserValueDelegate?

3. set the delegate on load (prepareForSegue)

    if(segue.identifier == "yourIdentifierInStoryboard") {

        var yourNextViewController = (segue.destinationViewController as yourNextViewControllerClass)
        yourNextViewController.delegate = self

4. add Function to FirstViewController

    func changeUser(toValue:Bool) {
        self.currentUserValue = toValue
    }

5. call this function from your SecondViewController

     delegate?.changeUser(true)

6. Set the delegate in your FirstViewController

    class FirstViewController: UIViewController, ChangeUserValueDelegate {

The problem here is that your currentUser variable is of type Bool, which is a value type. So passing it from your first view controller to your second view controller will in fact create a new Bool instance. What you need is to pass a reference from your first view controller to your second view controller (see Value and Reference Types for more details on value and reference with Swift).

Thereby, according to your needs/preferences, you may choose one of the three following examples.


1. The boxing style

Here, we "box" our Bool inside a class and pass a reference of that class instance to the second view controller.

1.1. Create a CurrentUser class:

class CurrentUser {
    var someBooleanValue = true {
        didSet {
            print(someBooleanValue)
        }
    }
}

1.2. Create a UIViewController subclass for the first view controller:

import UIKit

class ViewController1: UIViewController {

    let currentUser = CurrentUser()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        currentUser.someBooleanValue = false
    }
    
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if let viewController2 = segue.destinationViewController as? ViewController2 {
            viewController2.currentUser = currentUser
        }
    }

}

1.3. Create a UIViewController subclass for the second view controller:

import UIKit

class ViewController2: UIViewController {

    var currentUser: CurrentUser?

    // Link this IBAction to a UIButton or a UIBarButtonItem in the Storyboard
    @IBAction func toggleBoolean(sender: AnyObject) {
        if let currentUser = currentUser {
          currentUser.someBooleanValue = !currentUser.someBooleanValue
        }
    }
    
}

2. The closure style

Here, we get a weak reference of our first view controller in a closure and pass this closure to the second view controller.

2.1. Create a UIViewController subclass for the first view controller:

import UIKit

class ViewController1: UIViewController {
    
    var currentUser = true {
        didSet {
            print(currentUser)
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        currentUser = false
    }
    
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if let viewController2 = segue.destinationViewController as? ViewController2 {
            let closureToPerform = { [weak self] in
                if let strongSelf = self {
                    strongSelf.currentUser = !strongSelf.currentUser
                }
            }
            viewController2.closureToPerform = closureToPerform
        }
    }
    
}

2.2. Create a UIViewController subclass for the second view controller:

import UIKit

class ViewController2: UIViewController {

    var closureToPerform: (() -> Void)?

    // Link this IBAction to a UIButton or a UIBarButtonItem in the Storyboard
    @IBAction func toggleBoolean(sender: AnyObject) {
        closureToPerform?()
    }
    
}

3. The protocol-delegate style

Here, we make our first view controller conform to some protocol and pass a weak reference of it to the second view controller.

3.1. Create a custom protocol:

protocol MyDelegate: class {
    func changeValue()
}

3.2. Create a UIViewController subclass for the first view controller and make it conform to the previous protocol:

import UIKit

class ViewController1: UIViewController, MyDelegate {

    var currentUser = true {
        didSet {
            print(currentUser)
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        currentUser = false
    }
    
    func changeValue() {
        currentUser = !currentUser
    }
    
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if let viewController2 = segue.destinationViewController as? ViewController2 {
            viewController2.delegate = self
        }
    }

}

3.3. Create a UIViewController subclass for the second view controller:

import UIKit
    
class ViewController2: UIViewController {

    weak var delegate: MyDelegate?

    // Link this IBAction to a UIButton or a UIBarButtonItem in the Storyboard
    @IBAction func toggleBoolean(sender: AnyObject) {
        delegate?.changeValue()
    }
    
}

Add an attribute currentUserSecondVC in the destination view controller, and use prepareForSegue

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == "Name Of Your Segue" {
        var vc = segue.destinationViewController as NameOfTheSecondViewController
        vc.currentUserSecondVC = !currentUser //you can do whatever you want with it in the 2nd VC
    }
}