【问题标题】:Loading a switch state from NSUserDefault on load在加载时从 NSUserDefault 加载开关状态
【发布时间】:2016-09-30 02:22:04
【问题描述】:

我正在开发一个基本应用程序的设置视图。基本,在用户的设置视图中只有一个开关。开关设置与 NSUserDefault 一起保存。我使用委托将开关信号从设置视图发送到主视图。委派工作正常。

用户界面是基本的。在主视图上,标签将显示为绿色的 On(如果开关打开)和 Off 为红色(如果开关关闭)。右上角有一个设置按钮,将 (settingsSegue) 设置为 UITableViewController , UISwitch 所在的位置。

问题是在应用加载后加载 NSUserDefault。在 viewDidLoad 中,我检查是否有为 switch 键保存的值。如果有,请加载它。如果不是,请将其设置为 false(在情节提要中,默认情况下开关设置为 false。)开关状态每次加载为关闭。即使默认值为 On。这不应该发生。

ViewController.swift:

import UIKit

var nsDefaults = NSUserDefaults.standardUserDefaults()

class ViewController: UIViewController, SettingsViewControllerDelegate {

var onFromMain = Bool()

@IBOutlet weak var switchStateLabel: UILabel!


override func viewDidLoad() {
    super.viewDidLoad()

    if let mySavedKey = nsDefaults.objectForKey("savedSwitchSettingDefault") {
        // A value exists. Load it up.
        nsDefaults.objectForKey("savedSwitchSettingDefault")
        print("The switch is set! \(mySavedKey)")
        checkSwitchState()
    }
    else {
        // Nothing stored in NSUserDefaults yet. Set switch to False.
        nsDefaults.setBool(false, forKey: "savedSwitchSettingDefault")
        checkSwitchState()
    }

}


func myVCDidFinish(controller: SettingsViewController, switchState: Bool) {
    onFromMain = switchState.boolValue
    checkSwitchState()
}

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == "settingsSegue" {
        let nav = segue.destinationViewController as! UINavigationController
        let secondVC = nav.topViewController as! SettingsViewController
        secondVC.delegate = self
    }
}


func checkSwitchState() {
    if onFromMain {
        switchStateLabel.text = "On"
        switchStateLabel.textColor = UIColor.greenColor()
    }
    else {
        switchStateLabel.text = "Off"
        switchStateLabel.textColor = UIColor.redColor()
    }
}


}

SettingsViewController.swift:

import UIKit


protocol SettingsViewControllerDelegate {
func myVCDidFinish(controller: SettingsViewController, switchState: Bool)
}


class SettingsViewController: UITableViewController {


var delegate: SettingsViewControllerDelegate? = nil
@IBOutlet weak var switchOutlet: UISwitch!

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
    switchOutlet.on = nsDefaults.boolForKey("savedSwitchSettingDefault")
}

@IBAction func closeSettingsPageBarButtonItemPressed(sender: UIBarButtonItem) {

    if (delegate != nil) {
        delegate!.myVCDidFinish(self, switchState: switchOutlet.on)
        self.dismissViewControllerAnimated(true, completion: nil)
    }

}

@IBAction func switchPressed(sender: UISwitch) {
    // Tap the switch to change the setting.
    nsDefaults.setBool(switchOutlet.on, forKey: "savedSwitchSettingDefault")
}

}

我相信我的问题在于加载“savedSwitchSettingDefault”的默认键。它是否正确?还是问题出在代码的其他地方?

【问题讨论】:

  • 您将保存的值提取到mySavedKey,但随后不对该变量执行任何操作。然后你无缘无故地再次拨打objectForkey,无论如何你都应该使用boolForKey
  • @Paulw11 - 我更改了 if 语句以删除可选绑定。没有更多无用的财产。还在语句中将 objectForKey 更改为 boolForKey。我的评论中说明了“objectForKey”的原因。我正在检查它的值是否已经存在。该应用程序应该可以正常运行,而用户无需在设置中更改 UISwitch。现在,它没有。这一切有意义吗?谢谢!
  • 如果你使用boolForKey,如果密钥不存在,你只会得到false,无论如何这是你的默认值。第一次设置为true时会保存一个值,所以不需要整个if nil的东西。

标签: ios swift settings nsuserdefaults


【解决方案1】:

您可以依靠您想要的默认值是false 并且当密钥不存在时boolForKey 为您提供false 的事实来进行相当多的整理。

此外,通过访问viewWillAppear 中的设置,您可以避免委托回调。

ViewController.swift

import UIKit

class ViewController: UIViewController {

    let nsDefaults = NSUserDefaults.standardUserDefaults()

    var onFromMain = false

    @IBOutlet weak var switchStateLabel: UILabel!

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)

        self.onFromMain = self.nsDefaults.boolForKey("savedSwitchSettingDefault")

        self.checkSwitchState()
    }   

    func checkSwitchState() {
        if self.onFromMain {
            switchStateLabel.text = "On"
            switchStateLabel.textColor = UIColor.greenColor()
        }
        else {
            switchStateLabel.text = "Off"
            switchStateLabel.textColor = UIColor.redColor()
        }
    }
}

SettingsViewController.swift:

import UIKit

class SettingsViewController: UITableViewController {

    let nsDefaults = NSUserDefaults.standardUserDefaults()
    @IBOutlet weak var switchOutlet: UISwitch!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        self.switchOutlet.on = self.nsDefaults.boolForKey("savedSwitchSettingDefault")
    }

    @IBAction func closeSettingsPageBarButtonItemPressed(sender: UIBarButtonItem) {
        self.dismissViewControllerAnimated(true, completion: nil)
    }

    @IBAction func switchPressed(sender: UISwitch) {
    // Tap the switch to change the setting.
        self.nsDefaults.setBool(self.switchOutlet.on, forKey: "savedSwitchSettingDefault")
    } 
}

【讨论】:

  • 这正是我需要它做的,并且使用了更少的代码。赢/赢!谢谢您的帮助!但是问题-您能否进一步详细说明-“此外,通过访问 viewWillAppear 中的设置,您可以避免需要委托回调。”?由于我没有向设置视图发送任何信息,我只是在该视图中进行更改,因此是否有必要删除代表?
  • 没错;当您从设置视图返回主视图时,会调用 viewWillAppear。由于此函数从 NSUserDefaults 获取当前值,因此您不需要显式委托调用来更新值
  • 太棒了。谢谢你。我在您的代码中注意到的另一件事是您将删除的“nsDefaults”作为全局属性,并将其设置为两个视图中的类级别属性。这是什么原因?
  • 最好避免使用全局变量。在这种情况下,与获取全局值相比,向系统询问单例实例的开销基本上为零,因此保持全局没有任何好处
  • 完美。这就说得通了。以后我会牢记这一点!
【解决方案2】:

当从 User Defaults 中检索 bool 值时,boolForKey 将在该值不存在时返回 false。所以在这种情况下,不需要解包。来自文档:

如果布尔值与用户默认值中的 defaultName 相关联,则返回该值。否则,返回 false。

如果值正在设置(您确定),并且应用程序的行为无法正常工作,您的问题可能出在其他地方。

我建议使用另一种方法,将“onFromMain”声明为可选布尔值,然后在需要时将其解包。

var onFromMain: Bool?

... 

func checkSwitchState() {
    //- This will unwrap your optional or set false if its nil
    let switchSate = onFromMain ?? false 
    //- Then you can set the values based on the value (or the default false)
    switchStateLabel.text = switchState ? "On" : "Off"
    switchStateLabel.textColor = switchState ? UIColor.greenColor() : UIColor.redColor()
}

然后用断点附加调试器并查看该值是否被解包或者它是否默认为 false。

此外,您仅在调用 segue 时设置您的委托,这取决于场景,如果我理解正确,则在您实际导航到设置视图之前,您可能不会获得该值。因此,当打开应用程序(不导航到设置视图)时,onFromMain 将永远不会被填充。

或者,您可以在加载应用程序时立即获取视图 did load 方法上的值。

【讨论】:

    猜你喜欢
    • 2017-12-29
    • 1970-01-01
    • 1970-01-01
    • 2014-04-30
    • 2010-11-12
    • 2021-01-10
    • 1970-01-01
    • 2020-11-05
    • 1970-01-01
    相关资源
    最近更新 更多