【问题标题】:Passing data with unwind segue使用 unwind segue 传递数据
【发布时间】:2016-05-20 17:15:18
【问题描述】:

我创建了两个视图控制器。我从第一个到第二个创建了一个 segue 来传递数据。现在我想将数据从第二个视图控制器传递给第一个。我经历了许多类似的问题,但我无法实施这些问题,因为我缺乏关于展开如何工作的知识。

ViewController.swift

class ViewController: UIViewController
{   
    var dataRecieved: String?
    @IBOutlet weak var labelOne: UILabel!
    @IBAction func buttonOne(sender: UIButton)
    {
        performSegueWithIdentifier("viewNext", sender: self)
    }
    override func prepareForSegue(segue: (UIStoryboardSegue!), sender: AnyObject!)
    {

        var svc: viewControllerB = segue.destinationViewController as! viewControllerB
        svc.dataPassed = labelOne.text
    }
}

这会将数据传递给视图控制器“viewControllerB”中的 dataPassed。说,现在我想将一些数据从 viewControllerB 传递给 ViewController 中的 dataRecieved。我怎样才能只使用 unwind segue 而不是使用委托来做到这一点。我对 swift 很陌生,希望能得到详细的解释。

【问题讨论】:

  • 只需在展开视图控制器中实现prepareForSegue 并访问destinationViewController,这将是您要展开的视图控制器。您可能希望在情节提要中提供展开转场和标识符
  • 它给出了一个错误“没有带有标识符'btnSubmitSegue''的segue”。我在视图控制器中添加了 segue 标识符。我只使用一个 segue 来连接两个视图控制器。我相信 unwind segue 只是回到它以前的视图控制器而没有任何额外的 segues?你能详细解释一下吗?一些代码将不胜感激:)
  • 您照常创建展开转场 - 拖动到场景中的 exit 图标。现在在左侧的对象检查器中,您将看到在视图控制器、第一响应者和退出图标下方列出的展开转场。你可以点击 unwind segue 并在右侧的检查器中给它一个标识符。

标签: ios swift segue unwind-segue


【解决方案1】:

Øyvind Hauge 用同样的解决方案击败了我方法,但由于我已经开始提供更详细的答案,所以我也会添加它。


假设您的两个视图控制器命名如下:

  • 主控/入口点:ViewController(vcA)
  • 辅助视图:ViewControllerB(vcB)

你设置了从(vcA) -> (vcB) 开始的segue,就像你在你的例子中所做的那样

/* in ViewController.swift */   

// ...

// segue ViewController -> ViewControllerB
override func prepareForSegue(segue: (UIStoryboardSegue!), sender: AnyObject!)
{
    if segue.identifier == "viewNext" {
        let viewControllerB = segue.destinationViewController as! ViewControllerB
        viewControllerB.dataPassed = labelOne.text
    }
}

接下来有点棘手的步骤是,使用这种方法,用于将数据传回 from (vcB) to (vcA) 的 segue 也是 /em> 添加到(vcA) 的源中,作为@IBAction 方法(而不是像可能预期的那样,添加到(vcB) 的源中)。

/* in ViewController.swift */   

// ...

// segue ViewControllerB -> ViewController
@IBAction func unwindToThisView(sender: UIStoryboardSegue) {
    if let sourceViewController = sender.sourceViewController as? ViewControllerB {
        dataRecieved = sourceViewController.dataPassed
    }
}

之后,您可以通过(vcB) 中的手册Exit 将(vcB) 中的按钮连接到(vcA) 中的此展开操作:

下面是一个将文本从(vcA) 传递到(vcB) 的完整示例; (可能)通过UITextField 修改该文本,最后将(可能)修改后的文本返回给(vcA)。


(vcA)来源:

/* ViewController.swift: Initial view controller */
import UIKit

class ViewController: UIViewController {

    var dataRecieved: String? {
        willSet {
            labelOne.text = newValue
        }
    }
    @IBOutlet weak var labelOne: UILabel!

    @IBAction func buttonOne(sender: UIButton) {
        performSegueWithIdentifier("viewNext", sender: self)
    }

    // set default labelOne text
    override func viewDidLoad() {
        super.viewDidLoad()

        labelOne.text = "Default passed data"
    }

    // segue ViewController -> ViewControllerB
    override func prepareForSegue(segue: (UIStoryboardSegue!), sender: AnyObject!)
    {
        if segue.identifier == "viewNext" {
            let viewControllerB = segue.destinationViewController as! ViewControllerB
            viewControllerB.dataPassed = labelOne.text
        }
    }

    // segue ViewControllerB -> ViewController
    @IBAction func unwindToThisView(sender: UIStoryboardSegue) {
        if let sourceViewController = sender.sourceViewController as? ViewControllerB {
            dataRecieved = sourceViewController.dataPassed
        }
    }
}

(vcB) 源(注意这里的UITextFieldDelegate 委托仅用于“本地”改变dataPassed 属性的值,它将返回到(vcA) 并分配给dataRecieved 的属性后者)

/* ViewControllerB.swift */
import UIKit

class ViewControllerB: UIViewController, UITextFieldDelegate {

    var dataPassed : String?
    @IBOutlet weak var textField: UITextField!

    // set default textField text to the data passed from previous view.
    override func viewDidLoad() {
        super.viewDidLoad()

        textField.text = dataPassed

        // Handle the user input in the text field through delegate callbacks
        textField.delegate = self
    }


    // UITextFieldDelegate
    func textFieldShouldReturn(textField: UITextField) -> Bool {
        // User finished typing (hit return): hide the keyboard.
        textField.resignFirstResponder()
        return true
    }

    func textFieldDidEndEditing(textField: UITextField) {
        dataPassed = textField.text
    }
}

示例执行:

【讨论】:

  • 非常感谢您的详细解释!这有助于我更好地理解:)
  • 也许它就在我面前,但是'willSet { labelOne.text = newValue }'中的'newValue'是什么
  • @DarkhorseFantasySports 不用担心:这是要设置的新值的默认名称:"如果您实现 willSet 观察者,它会将新属性值作为常量参数传递。您可以为此参数指定一个名称作为您的willSet 实现的一部分。如果您不在您的实现中写入参数名称和括号,则该参数可以使用默认参数名称newValue。" - 来自the Swift Language Guide - Properties。
  • 我想这是最好的答案,并且作为 iOS 新手必须学习一些有趣的东西,因为我知道委托是将数据传回视图控制器的唯一方法,并且还了解了这个“新价值”的东西!感谢您的回答。
  • 在 Swift 4.0 中,名称似乎已更改。sender.sourceViewController -> sender.source。
【解决方案2】:

我会这样做:

  1. 在视图控制器 1 中创建一个 outlet,如下所示:

    @IBAction func unwindToViewController1(segue: UIStoryboardSegue) {
    
       let foo = segue.sourceViewController.foo
    
       // TODO: Use foo in view controller 1
    }
    
  2. 如下所示连接视图控制器 2(您要从中展开的 vc)。从 vc2 中的黄色圆圈拖动到“退出”。视图控制器 1 中的 IBAction 应该会弹出。选择它。

  3. 现在,每当您从视图控制器 2 中放松时,都会调用视图控制器 1 中的 unwindToViewController1: 方法。

  4. 您可以在此处从视图控制器 2 中检索所需的属性。请注意,您需要将 segue.sourceViewController 强制转换为您的自定义视图控制器子类才能获得正确的属性。

【讨论】:

  • 谢谢!这回答了我的问题:)
【解决方案3】:

如果您的应用支持 iOS 9+,您可以传递几乎与 prepareForSegue 相同的数据,请使用 UIStoryboardUnwindSegueSource,它的 sender 属性与 prepare(for segue: UIStoryboardSegue, sender: Any?) 中的 sender 属性完全相同。

使用方法:

  1. 创建一个 unwindTo 方法。

注意:连接 unwindTo 方法与@Øyvind Hauge 和@dfri 在他们的答案中解释的相同。

  1. 在要展开的视图控制器内部,覆盖方法canPerformUnwindSegueAction(_:from:withSender:)
  2. 在此方法中,检查 fromViewController 类型是否是您来自的类型
  3. 如果是,请将 sender 属性转换为您发送的类型并返回 true
  4. 否则,返回 false

代码片段(Swift 4.0):

@IBAction func unwindToMyFirstViewController(segue: UIStoryboardSegue) {}

override func canPerformUnwindSegueAction(_ action: Selector, from fromViewController: UIViewController, withSender sender: Any) -> Bool {
    if fromViewController is MyCustomViewController,
        let customType = sender as? MyCustomType {
        return true
    }
    return false
}

【讨论】:

    猜你喜欢
    • 2015-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-29
    • 2016-12-20
    • 1970-01-01
    • 2015-01-13
    • 1970-01-01
    相关资源
    最近更新 更多