从其他 viewController 访问 Swift 中的 UserDefaults

Posted

技术标签:

【中文标题】从其他 viewController 访问 Swift 中的 UserDefaults【英文标题】:Accessing UserDefaults in Swift from other viewControllers 【发布时间】:2017-03-05 16:34:25 【问题描述】:

在我的应用程序中,我使用 UserDefaults 来存储用户的登录状态(无论他们是否登录),以及他们的用户名。它工作正常,当我登录时,关闭应用程序,然后再次打开它,我的应用程序跳过登录页面并识别出我已经登录。虽然,我现在正在尝试将注销按钮安装到单独的 viewController。单击时,此注销按钮需要 1.) 将 UserDefaults.loginStatus 重置为“False” 2.) 将 UserDefaults.username 重置为 nil 3.) 对登录页面执行 segue。

这是我的 ViewController.swift 文件中的相关代码。这是第一个控制 loginPage 的 viewController。

import UIKit
import Firebase

let defaults = UserDefaults.standard

class ViewController: UIViewController 
func DoLogin(username: String, password: String) 
    //I Am not including a lot of the other stuff that takes place in this function, only the part that involves the defaults global variable
    defaults.setValue(username, forKey: "username")
    defaults.setValue("true", forKey: "loginStatus")
    defaults.synchronize()
    self.performSegue(withIdentifier: "loginToMain", sender: self) //This takes them to the main page of the app


override func viewDidLoad() 
    super.viewDidLoad()
    if let stringOne = defaults.string(forKey: "loginStatus") 
        if stringOne == "true"  //If the user is logged in, proceed to main screen
            DispatchQueue.main.async
                
                    self.performSegue(withIdentifier: "loginToMain", sender: self)
            
        
    


下面是我在 SecondViewController.swift 中的代码,尤其是注销功能。

import UIKit
import Firebase

class SecondViewController: UIViewController 
    override func viewDidLoad() 
        super.viewDidLoad()
     if let username = defaults.string(forKey: "username") 
            checkAppSetup(username: username) //This is an unrelated function
            //I included this because this works fine. Proving that I am able to read the defaults variable fine from this other viewController
      

@IBAction func logout(_ sender: Any) 
        defaults.setValue("false", forKey: "username")
        defaults.setValue("false", forKey: "loginStatus")
        defaults.synchronize()

        performSegue(withIdentifier: "logoutSegue", sender: nil)
    

运行注销功能时,segue 执行良好,但默认值不会更改。有人可以解释为什么以及我可以做些什么来解决这个问题吗?

**旁注,我实际上不会将默认值设置为“false”和“false”。在我调试此问题时,这只是暂时的。

【问题讨论】:

这里defaults.setValue("true", forKey: "loginStatus") 你正在设置true。这是正确的吗?出于调试目的?我想应该是false 是的,这是我问这个问题时的错字。在真正的代码中,它确实说“假”。谢谢你。但无论哪种方式,当我在 ViewController.swift 中访问它时,我在 SecondViewController 中设置的任何内容都不会出现 你能在performSegue(withIdentifier: "logoutSegue", sender: nil)这一行设置断点并在控制台中输入这个:po UserDefaults.standard.value(forKey: "loginStatus"),看看它会返回什么truefalse 我相信 Duncan C 在下面回答了我的问题,我只需要使用 .set(_ , forKey: "") 而不是 .setValue。但是谢谢你的想法! 【参考方案1】:

几件事。

您应该使用set(_:forKey:)object(_:forKey) 来读取键/值对并将其写入默认值,而不是setValue(_:forKey)。 (不过,您对defaults.string(forKey: "loginStatus") 的使用是正确的。)

您可能应该将 nil 写入 userName 键:

defaults.set(nil, forKey: "username")

您的注销IBAction 几乎可以肯定将loginStatus 设置为false,而不是true

尝试改变这些东西。

此外,除非您在 Xcode 中终止应用程序而不是按下设备/模拟器上的主页按钮以使其正常退出,否则没有理由调用 synchronize。

【讨论】:

效果很好!如果您不介意解释,.set 和 .setValue 之间究竟有什么区别?此外,.synchronize 究竟做了什么? setValue:forKey: 函数是一种 KVC(键值编码)方法,适用于任何 NSObject 以设置其值。我认为它不适用于UserDefaults.synchronize 函数强制 UserDefaults 立即写入磁盘。它相对昂贵,所以你应该只在你的应用程序可能在它有机会保存你对默认值的更改之前被终止时使用它(比如当你在 Xcode 中按下命令期间以在开发过程中终止应用程序时,或者如果你使用 force-quit来自跳板。) 明白。感谢您的出色回答和出色的解释!【参考方案2】:

嘿,我最近使用了完全相同的概念:

1) 在您的初始视图中,在viewDidLoad() 中,检查是否有人已经登录,并且一次只能有一个用户登录一台设备,所以我们检查一下

let defaults = UserDefaults.standard
if defaults.object(forKey: "userName") != nil && defaults.object(forKey: "userPassword") != nil
   
          let loginObject = self.storyboard?.instantiateViewController(withIdentifier: "YourSecondViewController") as! YourSecondViewController
//As someone's details are already saved so we auto-login and move to second view    

2) 在您的登录按钮功能中,检查您要检查的任何条件,然后在同一个内部,如果条件满足,则将数据保存到 userDefaults。

// If no details are saved in defaults, then control will come to this part, where we will save the entered userName and Password

    let defaults = UserDefaults.standard
    defaults.set(self.enteredUseName, forKey: "userName")
    defaults.set(self.enteredPassword, forKey: "Password")
    defaults.synchronize()

3) 在注销按钮上,删除userDefaults 并再次加载登录视图:

let defaults = UserDefaults.standard
defaults.removeObject(forKey: "userName") //We Will delete the userDefaults
defaults.removeObject(forKey: "userPassword")
defaults.synchronize() //Sync. the defaults.
navigationController?.popToRootViewController(animated: true) //Move Back to initial view.

4) 如果您使用导航控件,则必须使用 :P,那么您肯定会看到后退按钮,如果单击该按钮将打开第二个视图,因为您可以在viewDidLoad() 中隐藏导航栏您的登录视图

  self.navigationController?.navigationBar.isHidden = true

【讨论】:

以上是关于从其他 viewController 访问 Swift 中的 UserDefaults的主要内容,如果未能解决你的问题,请参考以下文章

ios - 无法从其他视图控制器访问数据

s3c2440——swi异常

SWI Prolog程序可以从外部数据库获取其事实吗?

从 ViewController 访问视图

需要从另一个viewController调用其他viewController中的方法

如何从 AppDelegate 访问 ViewController 变量