David Seek David Seek - 7 months ago 33
Swift Question

Swift / NSURLSession JSON download / unexpectedly found nil while unwrapping an Optional value

I am downloading data and handling it using the following code in the

viewDidLoad()
:

NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: "http://api.fixer.io/latest?base=USD")!, completionHandler: { (data, response, error) -> Void in

// Check if data was received successfully
if error == nil && data != nil {
do {
// Convert NSData to Dictionary where keys are of type String, and values are of any type
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! [String:AnyObject]
// Access specific key with value of type String
let dollarToDollarDict = json["rates"] as! NSDictionary
SpeedLog.print(dollarToDollarDict)
let dollarToDollarNSNumber = dollarToDollarDict.valueForKey("EUR")
let dollarToDollarString = String(dollarToDollarNSNumber)
SpeedLog.print(dollarToDollarString)
self.dollarExchangeRateStr = dollarToDollarString
} catch {
// Something went wrong
}
}
}).resume()


print(dollarToDollarDict)
prints out the correct Dictionary.
print(dollarToDollarString)
prints out the correct desired String I want to have as: "Optional(1.1303)"

But when I want to use the String in
dollarToDollarString
by having a button pressed, with:

func dollarBtnFunc(button: UIButton!) {

if dollarExchangeRateStr != "" {
SpeedLog.print("DOLLAR downloaded", dollarExchangeRateStr)
let dollarExchangeRateDouble = Double(dollarExchangeRateStr)!
tableCounterData = ["\(numberInt) $", "\(numberInt * dollarExchangeRateDouble) €"]

} else if dollarExchangeRateStr == "" {
SpeedLog.print("DOLLAR not downloaded, Dollar = 0.89")
tableCounterData = ["\(numberInt) $", "\(numberInt * 0.89) €"]
}
currentButton = "dollarBtnFunc"
}


I get
unexpectedly found nil while unwrapping an Optional value
on
let dollarExchangeRateDouble = Double(dollarExchangeRateStr)!
.

What am I missing? Why is the String
nil
? I have printed the correct value earlier... Why is it not part of my String anymore once I want to use it later? Help is very appreciated.

dan dan
Answer

Your problem is in these 2 lines:

let dollarToDollarNSNumber = dollarToDollarDict.valueForKey("EUR")
let dollarToDollarString = String(dollarToDollarNSNumber)

dollarToDollarDict.valueForKey("EUR") returns an optional, so dollarToDollarNSNumber is an optional.

Calling the String initializer with an optional gives the string "Optional(...)" so when you later pass that string to the Double initializer it fails because it has letters in it.

You need to unwrap the value you get from valueForKey by doing something like this:

if let dollarToDollarNSNumber = dollarToDollarDict.valueForKey("EUR") {
    let dollarToDollarString = String(dollarToDollarNSNumber)
    SpeedLog.print(dollarToDollarString)
    self.dollarExchangeRateStr = dollarToDollarString
} else {
    self.dollarExchangeRateStr = ""
}
Comments