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
}
}