Rory Zipher
Rory Zipher

Reputation: 255

Swift correct approach to nil value

Reading about Optional values I was sure that all the bases were covered in my code, but I still get the dreaded unexpectedly found nil while unwrapping an Optional value.

That makes sense, since I've read: What does “fatal error: unexpectedly found nil while unwrapping an Optional value” mean?. It suggests making the Int optional, which is what I want:

func myCountUpdate(mainDict: [String : NSObject]) {

    let myDict = mainDict["start"] as! [String : CFString]
    let myCount = subDict["count"] as? String
    let myTotal = Int(myCount)? // nope, it forces me to use non-optional !

    // as the other thread suggest it's easy to check for nil with an optional int.
    // how the hell can you do that if it won't allow you to make it optional?

    if myTotal != nil {
        print(myCount!)
        let label: String = "\(myCount)"
        text = label
    } else {
        text = nil
    }
}

I've tried quite a bunch of things, including using other values to check for nil, etc. The issue is that the compiler will not allow me to declare the Int as non-optional, so what are my options? Xcode shows no warnings or suggestions on this issue, so maybe someone here has one - ty.

Upvotes: 1

Views: 887

Answers (2)

Wilson
Wilson

Reputation: 9136

First unwrap the variable optional myCount(String?) to a variable called count (String).

let myCount = mainDict["count"] as? String

if let count = myCount {
   //..
}

Then try to create a Int based on the variable count (String).

Which could return a nil since you could pass Int("Hi") or Int("1").

myTotal = Int(count)

Then after that you will have a variable called myTotal (Int?) with the result that you want.


Code

func myCountUpdate(mainDict: [String : Any]) {

  let myDict = mainDict["start"] as? [String : Any]

  if let myCount = myDict?["count"] as? String {
    if let myTotal = Int(myCount) {
      print(myTotal)
    }
  }

  if let myCount = myDict?["count"] as? Int {
    print(myCount)
  }

}

Example 1

let data = [
  "start": [
    "count": "1"
  ]
]

myCountUpdate(mainDict: data) // outputs 1

Example 2

let data1 = [
  "start": [
    "count": 1
  ]
]

myCountUpdate(mainDict: data1) // outputs 1

Upvotes: 2

Federico Ojeda
Federico Ojeda

Reputation: 768

The best approach here is to use swift guards in order to check if a value is nil.

First, in the second line, where you use the subDict, its not referenced anywhere else, should it be myDict ?

The thing here is that the cast in let myCount = subDict["count"] as? String may be returning nil or there is not "count" in subDict. Therefore, when you do Int(myCount!), the force unwrapp of myCount is throwing the exception, since its nil.

You should avoid force unwrappings as much as you can, unless you are 100% sure that the value is not nil. In other cases, you should use the setting of a variable to check if it is not nil.

With your code, an updated version using guard would be the following:

func myCountUpdate(mainDict: [String : NSObject]) {
    guard let myDict = mainDict["start"] as? [String : CFString], 
          let myCount = myDict["count"] as? String, 
          let myTotal = Int(myCount) else {
       text = nil
       return
    }

    print(myTotal)
    let label: String = "\(count)"
    text = label
}

This is safer, because if any of the conditions in the guard fails, then it's setting the text to nil an ending the method.

Upvotes: 3

Related Questions