2

I have an "if let" statement that is being executed, despite the "let" part being nil.

if let leftInc : Double? = self.analysis.inputs[self.btnLeftIncisor.dictionaryKey!]! {
    println(leftInc)
    let valueString : String = formatter.stringFromNumber(NSNumber(double: leftInc!))!
    self.leftIncisorTextField?.text = valueString
    self.btnLeftIncisor.associatedLabel?.text = valueString
}

// self.analysis.inputs is a Dictionary<String, Double?>

The inputs dictionary holds information entered by the user - either a number, or nil if they haven't entered anything in the matching field yet.

Under the previous version of Swift, the code was written as this:

if let leftInc : Double? = self.analysis.inputs[self.btnLeftIncisor.dictionaryKey!]?? {

and worked correctly.

I saw a similar question here, but in that instance the problem seemed to be the result of using Any?, which is not the case here.

Community
  • 1
  • 1
Tim
  • 75
  • 1
  • 7

4 Answers4

2

The if-let is for unwrapping optionals. You are allowing nil values by setting the type to an optional Double.

The if statement should be:

if let leftInc = self.analysis.inputs[self.btnLeftIncisor.dictionaryKey!] as? Double{
...
}

This will attempt to get an object out of inputs, if that fails it returns nil and skips it. If it does return something it will attempt to convert it to a Double. If that fails it skips the if statement as well.

if inputs is a dictionary like [Something:Double] then you don't need the last as? Double as indexing the dictionary will return a Double?

I recommend reading the swift book on optional chaining.

utahwithak
  • 6,235
  • 2
  • 40
  • 62
  • I tried entering the code and got the error "Downcast from 'Double??' to 'Double' only unwraps optionals; did you mean to use '!!'? – Tim May 21 '15 at 16:16
2

Swift 2.2

In your if let you define another optional, that's why nil is a legitimate case. if let is intended mainly to extract (maybe) non optional value from an optional. You might try:

if let leftInc : Double = self.analysis.inputs[self.btnLeftIncisor.dictionaryKey!].flatMap ({$0}) {
   // leftInc is not an optional in this scope
   ...
}

Anyway I'd consider to not do it as a one liner but take advantage of guard case. Just in order to enhance readability. And avoid bang operator (!).

Community
  • 1
  • 1
Matteo Piombo
  • 6,688
  • 2
  • 25
  • 25
  • That makes sense. I had to add a "!" to the end, so now it reads "if let leftInc : Double = self.analysis.inputs[self.btnLeftIncisor.dictionaryKey!]! {" but it appears to be working now – Tim May 21 '15 at 16:14
  • This won't compile as the dictionary contains optional values, you're trying to get a non-optional double. The error will be something like 'Value of optional type Double?? not unwrapped...' – SomaMan Jul 22 '16 at 08:00
  • @SomaMan I've edited the answer to Swift 2.2. Hope this is still useful since the code in the question is not complete, and does not represent the actual intended data structure. – Matteo Piombo Jul 24 '16 at 18:08
0

You could break it down further -

if let optionalDouble = self.analysis.inputs[self.btnLeftIncisor.dictionaryKey!], leftInc = optionalDouble {
    ....
}

as your dictionary has optional values - this way of writing it might make it clearer what's going on

SomaMan
  • 4,127
  • 1
  • 34
  • 45
0

if let k = dict["someKey"]{}, dict["someKey"] will be an object of type Any this can bypass a nill So do a typecast to get it correct like if let k = dict["someKey"] as! String {}

slfan
  • 8,950
  • 115
  • 65
  • 78
Vikas Krishnan
  • 241
  • 2
  • 7