Sending data with Segue with Swift

风格不统一 提交于 2019-11-26 11:45:17

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

The function that should be defined as override is:

open func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if (segue.identifier == "Segue Name Defined In Storyboard") {
        //set the property of the designated view controller with the value you need
    }
}

Since you're using same variable across the two Viewcontrollers, namely currentUser (type Bool).

So its better to make it a global variable in both classes.

When coming to global variable concept in swift.

Everything by default in swift is public, and thus if you declare something like this:

class FirstViewController: UIViewController {

    var someVariable: Boll = YES

    init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }
}

You can access it and set values as long as you have an instance of it:

var MySecondViewController: FirstViewController = FirstViewController(nibName: nil, bundle: nil)
var getThatValue = MySecondViewController.someVariable
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!