如何在 Swift 中的视图控制器之间传递数据?

Posted

技术标签:

【中文标题】如何在 Swift 中的视图控制器之间传递数据?【英文标题】:How do you pass data between view controllers in Swift? 【发布时间】:2014-08-09 05:22:59 【问题描述】:

我尝试在加载视图但未呈现数据时创建全局变量并更新信息。

全局变量

var viewName:String = ""
var viewDuration:String = ""
var viewPeriod:String = ""
var viewMinAmp:String = ""
var viewMaxAmp:String = ""
var viewStep:String = ""
var viewType:String = ""

除了全局变量之外,还有没有更有效的信息传递方式?

@IBOutlet var txtName: UITextField!
@IBOutlet var txtDuration: UITextField!
@IBOutlet var txtPeriod: UITextField!
@IBOutlet var txtMinAmp: UITextField!
@IBOutlet var txtMaxAmp: UITextField!
@IBOutlet var txtStep: UITextField!
@IBOutlet var txtType: UITextField!

override func viewDidLoad() 
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    setInfo(viewName, duration: viewDuration, period: viewPeriod, minAmp: viewMinAmp, maxAmp: viewMaxAmp, step: viewStep, type: viewType)


func setInfo(name: String, duration: String, period: String, minAmp: String, maxAmp: String, step: String, type: String) 
    txtName.text = name
    txtDuration.text = duration
    txtPeriod.text = period
    txtMinAmp.text = minAmp
    txtMaxAmp.text = maxAmp
    txtStep.text = step
    txtType.text = type

【问题讨论】:

在 UIViewControllers 中定义属性并在初始化该控制器时设置它们。不要使用全局变量,这是一种不好的做法。 如何从一个控制器访问另一个控制器的方法? @AndrewShmig 如何访问 Swift 中的其他方法? :) How do you share data between view controllers and other objects in Swift? 的可能重复项 查看this answer 了解基本示例。 【参考方案1】:

一种解决方案是从包含您希望传递给目标视图控制器的数据的视图控制器中覆盖 prepareForSegue(segue:sender:)。

override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) 
    if (segue.identifier == "YourSegueName") 
        //get a reference to the destination view controller
        let destinationVC:ViewControllerClass = segue.destinationViewController as! ViewControllerClass

        //set properties on the destination view controller
        destinationVC.name = viewName
        //etc...
    

【讨论】:

这在 Swift 2.1 中有效吗?我使用完全相同的代码,我得到“无法将 UIViewController 类型的值转换为指定类型 NextViewController” 我还没有在 Swift 2.1 中尝试过;但是,听起来您可能需要显式转换目标视图控制器。 let destinationVC:ViewControllerClass = segue.destinationViewController as ViewControllerClass 这还是需要使用全局变量。关于如何避免全局变量在视图控制器之间传递数据或者避免共享状态的任何想法 为什么创建ViewControllerClass的副本会改变真实事物的属性?【参考方案2】:

对于 Swift 3.0

final class Shared 
     static let shared = Shared() //lazy init, and it only runs once

     var stringValue : String!
     var boolValue   : Bool!

设置stringValue

Shared.shared.stringValue = "Hi there"

获取stringValue

 if let value = Shared.shared.stringValue 
        print(value)
 

适用于 3.0 以下的 Swift 版本

您可以使用单例类在视图之间传递数据。这是一种简单有效的方法。这是我的课程 ShareData.swift

import Foundation

class ShareData 
    class var sharedInstance: ShareData 
        struct Static 
            static var instance: ShareData?
            static var token: dispatch_once_t = 0
        

        dispatch_once(&Static.token) 
            Static.instance = ShareData()
        

        return Static.instance!
    


    var someString : String! //Some String

    var selectedTheme : AnyObject! //Some Object

    var someBoolValue : Bool!

现在我可以在我的ViewControllerOne 中设置上述变量。

//Declare Class Variable

let shareData = ShareData.sharedInstance

override func viewDidLoad() 
    self.shareData.someString ="Some String Value"

在我的ViewControllerTwo 中,我可以访问someString

let shareData = ShareData.sharedInstance
override func viewDidLoad() 
    NSLog(self.sharedData.someString) // It will print Some String Value

【讨论】:

这只是一个新的空白项目 这听起来是正确的方法,特别是如果实例在应用程序中是独一无二的,例如 userInfo,一次只能登录一个使用,因此可以是共享的单例实例。 我喜欢这种在控制器之间共享数据的方式!但是由于swift3.0在语法上有很多变化。你能更新一个 swift3.0 版本吗?@SaqibOmer 在线出现错误:" static var token: dispatch_once_t = 0 " " 'dispatch_once_t' 在 Swift 中不可用:改用延迟初始化的全局变量" @PhilipS 您使用的是哪个版本的 Swift?什么是错误?【参考方案3】:

就个人而言,我更喜欢以下方式:

如果你想在两个视图控制器之间跳转(从A到B),如-pushViewController:animated:在导航中,你可以为控制器B定义一个模型的属性并公开它,然后设置这个在从控制器 A 跳转之前显式设置属性,这非常简单;

如果您想从控制器 B 向后跳转到 A,请使用委托+协议模式。控制器 B 起草一个公共协议并拥有一个“委托”属性,任何想成为控制器 B 代表的对象都应遵守并实现其协议(可选)。然后在后跳之前,控制器 B 让其代理执行协议中列出的某些操作,数据可以通过这种方式传输;

在某些情况下,您可能希望将数据从一个控制器(或多个控制器)传输到其他多个控制器,如果是这种情况,请使用通知机制。

Apple 在官方文档中有关于委托模式、通知模式的详细说明,请在 XCode 中查看,:)

【讨论】:

【参考方案4】:

只需要执行 3 个步骤,假设您要将数据从 ViewControllerA 传递到 ViewControllerB:

    在 ViewControllerA 和 ViewControllerB 之间创建一个 segue 在它的属性检查器中用标识符命名segue 覆盖 ViewControllerA 处的 prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!)

对于第 3 步,

如果你没有使用 swift 2.1,请关注@Scott Mielcarski 's answer at this question

对于使用 swift 2.1 或遇到 错误“无法将类型 'UIViewController' 的值转换为指定类型'您的视图控制器类名',之后关注@Scott Mielcarski 's answer at this question,请使用let destinationVC:ViewControllerClass = segue.destinationViewController as! ViewControllerClass代替 let destinationVC:ViewControllerClass = segue.destinationViewController

这是在 Swift 2.1.1 上测试的,它对我有用。

【讨论】:

【参考方案5】:

如果您实际上不想在视图控制器之间传递数据,而只是想存储一个全局变量,您可以这样做:

这很好地解释了如何在 Swift 5 中执行此操作:https://www.hackingwithswift.com/example-code/system/how-to-save-user-settings-using-userdefaults

总结:

设置一个值:

let defaults = UserDefaults.standard
defaults.set("value", forKey: "key")

获取字符串值:

let key = defaults.object(forKey: "StringKey") as? [String] ?? [String]()

获取整数值:

let key = defaults.integer(forKey: "IntegerKey")

【讨论】:

以上是关于如何在 Swift 中的视图控制器之间传递数据?的主要内容,如果未能解决你的问题,请参考以下文章

在 Swift 中的视图控制器之间传递数据

在 Swift 中的页面视图控制器内的视图控制器之间传递数据

在 Swift 中的视图控制器之间传递自定义类数据

在 Swift 中的 ONE ViewController 中的视图之间传递数据

Swift - 在视图控制器之间传递数据

swift 4 中使用 performSegue 打开的关闭页面时,如何在视图控制器和 TableViewController 之间传递数据?