3

Hi my app crashes the first time I run it. This is my code:

 let State = save.stringForKey("StateSave")
 let City = save.stringForKey("CitySave")
 let Vehicle = save.stringForKey("ModelNumberSave")
 let ExtensionPeriod = save.stringForKey("ExtensionPeriodChoosed")
 let Location = "Location"


 if ExtensionPeriod == nil {
      let name = ""
      var FieldChoosed: Void = save.setObject(name, forKey: "ExtensionPeriodChoosed")
      save.synchronize()

 }

 save.synchronize()
 var DetailNames = ["\(State!)","\(City!)","\(Location)","\(Vehicle!)","\(ExtensionPeriod!)"]

I get a nil on this line:

var DetailNames = ["(State!)","(City!)","(Location)","(Vehicle!)","(ExtensionPeriod!)"]

In fact ExtensionPeriod is nil. But I don't understand why... ExtensionPeriod is nil, but with the code I write, ExtensionPeriod will be like "" so it's not nil. Please help me.

Airspeed Velocity
  • 40,491
  • 8
  • 113
  • 118
markutus
  • 603
  • 2
  • 8
  • 12

3 Answers3

8

stringForKey returns nil when there has not been a value saved already.

You need to give your values a default. The easiest way to do this is with the ?? operator, that replaces nil with another value:

let State = save.stringForKey("StateSave") ?? "-"

Some general advice: you need to stop using ! so much. Usually when something returns nil, it’s for a good reason – it might be nil. When you unwrap it with !, your program will crash (with not much helpful info as to why). Similarly, it’s usually a bad sign if you’re comparing values to nil.

Instead, take a look at this list of optional handling techniques for some alternatives.

Community
  • 1
  • 1
Airspeed Velocity
  • 40,491
  • 8
  • 113
  • 118
  • but if i don't put the "!" the text will be show as Optional. no? – markutus Jul 06 '15 at 19:09
  • There are lots of different ways for you to unwrap optionals, which are safer than `!`. Look at http://stackoverflow.com/a/27623568/3925941 and http://stackoverflow.com/a/29717211/3925941 for some examples. – Airspeed Velocity Jul 06 '15 at 19:28
1

Airspeed Velocity has a good solution for the proper way to accomplish what you want to do, but he did not really explain why what you did does not work, so I will address that aspect of this question.

if ExtensionPeriod == nil {
    let name = ""
    var FieldChoosed: Void = save.setObject(name, forKey: "ExtensionPeriodChoosed")
    save.synchronize()
}

That block of code does not set ExtensionPeriod, thus ExtensionPeriod is still nil. All it does is set the value for the key "ExtensionPeriodChoosed" in the NSUserDefaults to no longer be nil. The local variable ExtensionPeriod, however, still has nil. ExtensionPeriod doesn't just magically point to the variable stored in NSUserDefaults, such that when you update NSUserDefaults, it automatically updates the variable. Instead, it copies the variable at the time that it is created.

Here is some sample code that demonstrates this:

    NSUserDefaults.standardUserDefaults().setValue("string", forKey: "s")
    NSUserDefaults.standardUserDefaults().synchronize()
    var s = NSUserDefaults.standardUserDefaults().valueForKey("s")
    
    NSUserDefaults.standardUserDefaults().setValue("string2", forKey: "s")
    NSUserDefaults.standardUserDefaults().synchronize()
    var y = NSUserDefaults.standardUserDefaults().valueForKey("s")
    
    println(s)
    println(y)

outputs:

"string"

"string2"

For your code to work, if you were to keep it the same structure (although you really shouldn't), you would need to change ExtensionPeriod to a var, and then in your if block, after you synchronize save, you would have to reassign ExtensionPeriod to save.valueForKey("ExtensionPeriodChoosed").

Community
  • 1
  • 1
Will M.
  • 1,864
  • 17
  • 28
1

One way to make sure that your app's defaults are set is to use NSUserDefault's registerDefaults(_: [NSObject : AnyObject]) function. In Objective-C, I often put in the + (void)initialize class method, but overriding the init() of the application delegate should work just as well.

MaddTheSane
  • 2,981
  • 24
  • 27