-1

As the title states, I am receiving the "fatal error: unexpectedly found nil while unwrapping an Optional value" error. My JSON is valid, and the link can be found here: http://www.mocky.io/v2/5844d2801100001d140e6b91 .

The line of code that is giving me an issue is here:

let fighterDetails = dictionary["Fighters"]! as! [[String:AnyObject]]

At one point, I had all working code. I went back and re-structed my entire code as I decided to change the topic. I fixed all other errors, but I'm left with this at run-time.

image json receiver

Kevin
  • 49
  • 1
  • 9
  • Clearly, `dictionary["Fighters"]` isn't a `[[String: AnyObject]]` – Alexander Dec 05 '16 at 03:00
  • My professor has a similar line of code in his project example which is " let customerDetails = dictionary["Customers"]! as! [[String:AnyObject]]" . Customers is an object. His works. What's the difference? – Kevin Dec 05 '16 at 03:02
  • 4
    Any time you use ! with external data, a little bunny dies and your program may crash. Also, your JSON doesn't contain the string "Fighters" anywhere. It does contain "Customers". Use conditional unwrapping – Paulw11 Dec 05 '16 at 03:11
  • @Paulw11 - I had "Customers" instead of "Fighters" - Thank you very much! – Kevin Dec 05 '16 at 03:14
  • @Paulw11, you just gave me the best laugh of the day with the dying bunny line. Thank you. – Duncan C Dec 05 '16 at 03:28
  • 2
    @Kevin, think of the `!` operator as the "crash if nil" operator, and avoid it like the plague until you **really** know what you're doing. It says "I know what I'm doing. This expression WILL resolve correctly. I stake my life on it." Unless you are 100% bet-your-program's-life-on-it-certain that the expression will evaluate successfully, don't use it. – Duncan C Dec 05 '16 at 03:30
  • 2
    Exactly what @DuncanC said. Your program crashes because you ASKED the compiler to write you a program that crashes when your assertions don't hold true (in this case, the assertion that `dictionary` contains a value of type `[[String: AnyValue]]` for the key `"Fighters"`. – Alexander Dec 05 '16 at 03:35

2 Answers2

2

When parsing remote JSON data, you should never use the ! operator. Instead, use guard statements when unwrapping:

guard let fighterDetails = dictionary["Fighters"] as? [[String:AnyObject]] else {
    return []
}

And use try? instead of try!.

For the client developer, I recommend the usage of SwiftLint to help you use better Swift practices. It would have detected the issue with as!.

For the server developer, I recommend to stick to one lettercase convention. People tend to recommend camelCase when dealing with JSON keys. i.e., you should rename "Fighters" to "fighters" to align with "name", "country", ... It may have avoided the issue of your missing key.

Community
  • 1
  • 1
Cœur
  • 37,241
  • 25
  • 195
  • 267
  • Wise words. In my opinion, `!` is "The `goto` of Swift" :-) – Nicolas Miari Dec 05 '16 at 04:13
  • I'm waiting for the day Apple spares us from having to rely on `@IBOutlet weak var button: UIButton!` etc. – Nicolas Miari Dec 05 '16 at 04:14
  • @Cœur Great feedback. Thank you for this. – Kevin Dec 06 '16 at 03:55
  • I had to update the code you recommended to "guard let fighterDetails = dictionary["Fighters"] as? [[String:AnyObject]] else { return [:] as Any as! [Fighter] } " Can you explain the line "return [:] as Any as! [Fighter]" and why [:] wouldn't work as you recommended? The error it was giving was "contextual type Fighter cannot be used with dictionary literal" – Kevin Dec 06 '16 at 04:13
  • 1
    @Kevin, please don't cast as Any. I've updated my answer: you can simply `return []`. – Cœur Dec 06 '16 at 04:19
  • @Cœur - Thanks for your help and patience on the issue. – Kevin Dec 06 '16 at 13:43
1

I checked the json url and there's no key "Fighters" in there.

kiritoxcii
  • 27
  • 1
  • 8