使用Swift进行Segue数据传递

37

我有两个视图控制器和两个视图。

在我的第一个视图中,我将变量“currentUser”设置为false。

我需要能够在第二个视图控制器中将“currentUser”设置为true。

当尝试从第二个视图引用“currentUser”时,它无法被识别,因为“currentUser”是在第一个视图控制器中定义的。

如何通过segue传递变量?

5个回答

59

使用segue将任何ViewController的值设置到第二个ViewController中

像这样:

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

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

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

并且在你的 yourNextViewController 类中。

class yourNextViewControllerClass {

    var value:Int! // or whatever

你也可以通过编程的方式进行调用:

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

将DestinationViewController中的值设置回Primary(First)ViewController

1. 实现一个协议,例如创建一个名为protocol.swift的文件。

    protocol changeUserValueDelegate {
       func changeUser(toValue:Bool)
    }

2. 在你的第二个 View 上设置代理

    class yourNextViewControllerClass {

    var delegate:changeUserValueDelegate?

3. 在加载时设置委托(prepareForSegue)

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

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

4. 添加功能到 FirstViewController

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

5. 从你的SecondViewController调用此函数

     delegate?.changeUser(true)

6. 在您的FirstViewController中设置代理

    class FirstViewController: UIViewController, ChangeUserValueDelegate {

我不能使用函数来完成这个任务,我需要在“if”语句中实现。抱歉没有表达清楚。 - Alex Catchpole
通过这两种方法,您可以从第一个视图控制器向第二个视图控制器发送数据,并从第二个视图控制器返回到第一个视图控制器。在“if”语句中调用这个方法不应该是问题。 - derdida
我尝试了第一种方法,但是在if语句中无法使用override函数,在第二个视图控制器中找不到该变量。 - Alex Catchpole
1
非常好的解决方案。在找到这个方法之前,我搜索了很多关于如何回到 firstViewController 的方式。一个意外的好处是,现在我已经编写并使用了自己的协议! - Scooter
通过理解这种控制器间协议通信的变体,我有了一个启示。谢谢。 - Gunnar Forsgren - Mobimation

16
问题在于您的currentUser变量是Bool类型,这是一个值类型。因此,从第一个视图控制器传递到第二个视图控制器实际上会创建一个新的Bool实例。你需要的是从第一个视图控制器向第二个视图控制器传递一个引用(有关Swift中值和引用的更多详细信息,请参见值类型和引用类型)。
因此,根据您的需求/偏好,可以选择以下三个示例之一。

1. 封箱式

在这里,我们将Bool封装在一个类中,并将该类实例的引用传递给第二个视图控制器。

1.1. 创建一个CurrentUser类:

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

1.2. 为第一个视图控制器创建一个UIViewController子类:

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. 为第二个视图控制器创建一个UIViewController子类:

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. 闭包式编程

在这里,我们使用一个闭包获取第一个视图控制器的弱引用,并将此闭包传递给第二个视图控制器。

2.1. 为第一个视图控制器创建一个UIViewController子类:

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. 为第二个视图控制器创建一个UIViewController子类:

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. 协议代理模式

在这里,我们让第一个视图控制器遵循某个协议,并将其弱引用传递给第二个视图控制器。

3.1. 创建自定义协议:

protocol MyDelegate: class {
    func changeValue()
}

3.2. 为第一个视图控制器创建一个UIViewController子类,并使其符合先前的协议:

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. 为第二个视图控制器创建一个UIViewController子类:

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

1
在目标视图控制器中添加一个属性currentUserSecondVC,并使用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
    }
}

0
应该定义为覆盖的函数是:
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
    }
}

0

由于您在两个视图控制器中使用了相同的变量,即currentUser(类型为Bool),因此最好将其设置为两个类中的全局变量。

当涉及到Swift中的全局变量概念时。

在Swift中,默认情况下所有内容都是公共的,因此如果您声明了以下内容:

class FirstViewController: UIViewController {

    var someVariable: Boll = YES

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

只要您拥有它的实例,就可以访问并设置其值:

var MySecondViewController: FirstViewController = FirstViewController(nibName: nil, bundle: nil)
var getThatValue = MySecondViewController.someVariable

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接