1

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.

AtheistP3ace
  • 9,611
  • 12
  • 43
  • 43
Rory Zipher
  • 245
  • 1
  • 2
  • 10
  • 2
    Possible duplicate of [What does "fatal error: unexpectedly found nil while unwrapping an Optional value" mean?](http://stackoverflow.com/questions/32170456/what-does-fatal-error-unexpectedly-found-nil-while-unwrapping-an-optional-valu) – rmaddy Feb 10 '17 at 00:40
  • Read the answers in that duplicate. It explains the proper way to handle optional values. And using `!` is the opposite of what you should be using. – rmaddy Feb 10 '17 at 00:42
  • @rmaddy, The compiler won't let me use anything else though... that's where I'm stuck. I'm not a swift developer and I'm just trying to fix this one thing and move on... – Rory Zipher Feb 10 '17 at 00:44

2 Answers2

3

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.

Federico Ojeda
  • 758
  • 7
  • 11
  • Now it say "Initializer for conditional binding must have Optional type, not 'String'" for the `let count = myCount,` line. – Rory Zipher Feb 10 '17 at 01:10
  • Sorry, the `let count = myCount` slipped me. `myCount` is not optional actually. I updated the answer! – Federico Ojeda Feb 10 '17 at 01:14
  • Thanks, that sort of worked... (I had to change "count" to "myTotal" - you had two, one still is there), so you might want to fix that in your answer. Another issue is that if the `myDict[count]` value is not a string then it crashes... like if the value is an `Int` it will crash :(` – Rory Zipher Feb 10 '17 at 01:50
2

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
Wilson
  • 9,006
  • 3
  • 42
  • 46
  • Maybe an explanation of what you changed in the code could be useful to the OP and others who may come this way in the future. =] – AtheistP3ace Feb 10 '17 at 01:23
  • yea that's good. Just a suggestion so others can get an explanation of what happened. Thanks. I appreciate and I'm sure one day others may too!! – AtheistP3ace Feb 10 '17 at 01:34
  • 1
    What does `myDict` do? seems likes it's not being used.. app crashes now too - `unexpectedly found nil while unwrapping an Optional value`. The error in the code is `Initialization of immutable value 'myDict' was never used; consider replacing with assignment to '_' or removing it`. – Rory Zipher Feb 10 '17 at 01:41
  • There seems to be another mistake maybe in your code, and that is `subDict`? I don't have that. Also, like the other answer if the value of `myCount` is an integer and not a string it crashes and burns... – Rory Zipher Feb 10 '17 at 02:00