Joe Joe - 6 months ago 35
iOS Question

Loading a switch state from NSUserDefault on load

I am working on a settings view for a basic app. Basic, in there is just one switch in the settings view for the user. The switch setting is saved with NSUserDefault. I use a delegate to send the switch signal from the settings view to the main view. The delegation works properly.

The UI is basic. On the main view, a label will read On in green (if the switch is on) and Off in red (if the switch is off.) There is a setting button in the top right that will segue (settingsSegue) to the settings UITableViewController, where the UISwitch is located.

The problem is loading up the NSUserDefault once the app loads. In viewDidLoad, I check to see if there's a value saved for the switch key. If there is, load it up. If not, set it to false (in the storyboard, the switch is set to false as default.) The Switch Status loads up as Off every time. Even if the default value is On. This shouldn't be happening.

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

}


I believe my problem lies somewhere in loading up the default key for "savedSwitchSettingDefault". Is this correct? Or does the issue lie elsewhere in the code?

Answer

You can tidy things up quite a bit by relying on the fact that the default you want is false and that boolForKey gives you false when the key isn't present.

Also, by accessing the setting in viewWillAppear you can avoid the need for the delegate callback.

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