Issue with reading string from NSUserDefaults

Hey everyone!

I'm currently having an issue when reading a string value from NSUserDefaults in Swift for iOS.

I am using NSUserDefaults.standardUserDefaults() in order to store string data within the application by using a set of predefined keys. I know the predefined keys work due to other methods functioning correctly, but for whatever reason the value of these keys always returns as "" or nil.

Each text field saves its values when they are dismissed, but I can't seem to figure out what has gone wrong.

I feel as though the data should be saved properly after hitting the return button or touching on the view.

If you have any idea as to what I've done wrong I'd be so happy to hear what I can do to fix it!


Here is my code:

@IBOutlet weak var hotelNameField: UITextField!
@IBOutlet weak var roomNumField: UITextField!
@IBOutlet weak var hotelLbl: UILabel!
@IBOutlet weak var roomLbl: UILabel!

private var defaultKeys: DefaultKeys = DefaultKeys()
private var isEditingDate : Bool = Bool()

func handleUIForPages(var indexUsed: Int)
    {
        if(indexUsed == 0)
        {
            //This doesn't matter for this issue.
        }
        else if(indexUsed == 1)
        {
            handlePageTwo()
            hotelLbl.text = "Hotel Name:"
            roomLbl.text = "Room Number:"
            datePickerField.hidden = true
            datePickerLbl.hidden = true
            date2PickerField.hidden = true
            date2PickerLbl.hidden = true
            hotelNameField.hidden = false
            roomNumField.hidden = false
            hotelLbl.hidden = false
            roomLbl.hidden = false
            weatherNotificationsLbl.hidden = true
            weatherNotificationsSwitch.hidden = true
            welcomeMessageLbl.hidden = true
            welcomeMessageSwitch.hidden = true
            finishedLbl.hidden = true
            getStartedButton.hidden = true
            setupImageView.hidden = false
            setupImageView.image = UIImage(named: "LocationIcon")
        }
        else if (indexUsed == 2)
        {
            //This doesn't matter for this issue.
        }
        else if (indexUsed == 3)
        {
            //This doesn't matter for this issue.
        }
        else
        {
            println("Beyond normal index!")
        }
    }

func handlePageTwo()
    {
        var defaults : NSUserDefaults = NSUserDefaults.standardUserDefaults()
        var hotelName = defaults.valueForKey(defaultKeys.key5) as! String?
        var roomNumber = defaults.valueForKey(defaultKeys.key6) as! String?
    
        if(hotelName != "")
        {
            hotelNameField.text = hotelName
        }
        else
        {
            println("Hotel Name hasn't been entered")
        }
    
        if(roomNumber != "")
        {
            roomNumField.text = roomNumber
        }
        else
        {
            println("Room Number hasn't been entered")
        }
    }

func textFieldShouldReturn(textField: UITextField) -> Bool {
        var defaults: NSUserDefaults = NSUserDefaults.standardUserDefaults()
     
        var hotelData = hotelNameField.text
        var roomData = roomNumField.text
     
        defaults.setValue(hotelData, forKey: defaultKeys.key5)
        defaults.setValue(roomData, forKey: defaultKeys.key6)
     
        textField.resignFirstResponder()
        return true
    }

override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
     var defaults: NSUserDefaults = NSUserDefaults.standardUserDefaults()
     if(isEditingDate == false)
     {
          println("Editing is false")
          var hotelData = hotelNameField.text
          var roomData = roomNumField.text
         
          defaults.setValue(hotelData, forKey: defaultKeys.key5)
          defaults.setValue(roomData, forKey: defaultKeys.key6)
         
          self.view.endEditing(true)
     }
}

func handleRoomFieldDelegates()
{
     hotelNameField.delegate = self
     roomNumField.delegate = self
}

Thanks!

🙂

Are you hitting the "stop" button in Xcode then re-running the app to see if the value was stored? If so, the problem is likely that your defaults values haven't been written to disk yet since you're not calling synchronize() anywhere.


Some tutorials recommend calling it after every write, but that's overkill IMHO. I call it when the app moves to the background, and just have to remember to push the Home button before killing the app from Xcode if I want my defaults to be saved. The force terminate while the app is still alive is a highly unusual circumstance in the real world (will most likely only happen if you have a crash).

Accepted Answer

It looks like you are calling the wrong methods to set and get your values.


Instead of getting and setting your values like this:

var hotelName = defaults.valueForKey(defaultKeys.key5) as! String?

defaults.setValue(hotelData, forKey: defaultKeys.key5)


you probably need to do this:

var hotelName = defaults.objectForKey(defaultKeys.key5) as? String  // or just defaults.stringForKey(defaultKeys.key5)

defaults.setObject(hotelData, forKey: defaultKeys.key5)

D'oh!! Good thing somebody is paying attention 😀

But I even missed it in that other thread where I posted about the issue in the iOS playground; it's subtle.

Thank you so much! I didn't think about the fact that Strings are truly object. You have helped me so much! Thank you!

The setValue(forKey:) and valueForKey() methods are actually part of objective-C's key/value observing functionality which are inherited from NSObject, and not part of the NSUserDefaults methods for storing and retrieving values.

Issue with reading string from NSUserDefaults
 
 
Q