1

I found this question on parsing JSON in Swift 3 to be very helpful, but I noticed my JSON structure had an array for the "weather" key (see red arrow). I was able to parse other parts of the JSON output, but this array caused problems. Snapshot of Console

Question: Why am I not able to use the [String:Any] pattern that worked on other parts of this JSON data?.

This is my error in the console: Could not cast value of type '__NSSingleObjectArrayI' (0x112e04be0) to 'NSDictionary' (0x112e05108).

import UIKit

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        let url = URL(string: "http://api.openweathermap.org/data/2.5/weather?q=London,uk&appid=MYAPIKEY")!

        let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
            if error != nil {
                print(error)
            }else {
                if let urlContent = data {
                    do {
                        let parsedData = try JSONSerialization.jsonObject(with: urlContent, options: .allowFragments) as! [String:Any]
                        print(parsedData)
                       let currentCondions = parsedData["main"] as! [String:Any]

                        for (key, value) in currentCondions {
                            print("\(key) - \(value)")
                        }

                        let locationInfo = parsedData["sys"] as! [String:Any]
                        for (key, value) in locationInfo {
                            print("\(key) - \(value)")
                        }

                        let weatherMain = parsedData["weather"] as! [String:Any]
                        print(weatherMain)

                    } catch {
                       print("JSON processessing failed")
                    }//catch closing bracket
                }// if let closing bracket
            }//else closing bracket
        }// task closing bracket
        task.resume()
    }
}
Community
  • 1
  • 1
brickm
  • 75
  • 2
  • 9
  • Your issue isn't clear. Where in your code specifically is your issue? What is the actual issue? Compile error? Runtime error? Unexpected results? Be specific. – rmaddy Nov 28 '16 at 22:13
  • I updated the code and the question to show the issue in console. I get a "Thread 8: signal SIGABRT" with the following error in the console: Could not cast value of type '__NSSingleObjectArrayI' (0x112e04be0) to 'NSDictionary' (0x112e05108). – brickm Nov 28 '16 at 22:17

1 Answers1

3

The error makes the issue fairly clear (that, and looking at the output at the start of your question. The value for the "weather" key is not a dictionary. It's an array of dictionary.

So this:

let weatherMain = parsedData["weather"] as! [String:Any]

needs to be:

let weatherMain = parsedData["weather"] as! [[String:Any]]

As a side note, every use of ! in your app is a crash waiting to happen. You should be safely unwrapping and safely casting values that might not actually be what you think. I strongly suggest you spend some quality time reviewing the sections on optionals, type casting, and optional chaining in the The Swift Programming Language book.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
  • thanks for the quick reply and explaining the dictionary vs. array of dictionary. This was my first attempt at JSON ever. Your answer was spot on. I am a learner and can get stumped easily. I'll take your advice on not force unwrapping. I should get in the habit of wrapping it in something with error handling. – brickm Nov 28 '16 at 23:59