By user2563039

2016-09-10 06:43:15 8 Comments

I'm trying to fetch a JSON response and store the results in a variable. I've had versions of this code work in previous releases of Swift, until the GM version of Xcode 8 was released. I had a look at a few similar posts on StackOverflow: Swift 2 Parsing JSON - Cannot subscript a value of type 'AnyObject' and JSON Parsing in Swift 3.

However, it seems the ideas conveyed there do not apply in this scenario.

How do I correctly parse the JSON reponse in Swift 3? Has something changed in the way JSON is read in Swift 3?

Below is the code in question (it can be run in a playground):

import Cocoa

let url = ",122.048951"

if let url = NSURL(string: url) {
    if let data = try? Data(contentsOf: url as URL) {
        do {
            let parsedData = try JSONSerialization.jsonObject(with: data as Data, options: .allowFragments)

        //Store response in NSDictionary for easy access
        let dict = parsedData as? NSDictionary

        let currentConditions = "\(dict!["currently"]!)"

        //This produces an error, Type 'Any' has no subscript members
        let currentTemperatureF = ("\(dict!["currently"]!["temperature"]!!)" as NSString).doubleValue

            //Display all current conditions from API

            //Output the current temperature in Fahrenheit

        //else throw an error detailing what went wrong
        catch let error as NSError {
            print("Details of JSON parsing error:\n \(error)")

Edit: Here is a sample of the results from the API call after print(currentConditions)

["icon": partly-cloudy-night, "precipProbability": 0, "pressure": 1015.39, "humidity": 0.75, "precipIntensity": 0, "windSpeed": 6.04, "summary": Partly Cloudy, "ozone": 321.13, "temperature": 49.45, "dewPoint": 41.75, "apparentTemperature": 47, "windBearing": 332, "cloudCover": 0.28, "time": 1480846460]


@J. Doe 2019-01-11 09:30:42

Swift has a powerful type inference. Lets get rid of "if let" or "guard let" boilerplate and force unwraps using functional approach:

  1. Here is our JSON. We can use optional JSON or usual. I'm using optional in our example:

    let json: Dictionary<String, Any>? = ["current": ["temperature": 10]]

  1. Helper functions. We need to write them only once and then reuse with any dictionary:

    /// Curry
    public func curry<A, B, C>(_ f: @escaping (A, B) -> C) -> (A) -> (B) -> C {
        return { a in
            { f(a, $0) }

    /// Function that takes key and optional dictionary and returns optional value
    public func extract<Key, Value>(_ key: Key, _ json: Dictionary<Key, Any>?) -> Value? {
        return json.flatMap {

    /// Function that takes key and return function that takes optional dictionary and returns optional value
    public func extract<Key, Value>(_ key: Key) -> (Dictionary<Key, Any>?) -> Value? {
        return curry(extract)(key)

    /// Precedence group for our operator
    precedencegroup RightApplyPrecedence {
        associativity: right
        higherThan: AssignmentPrecedence
        lowerThan: TernaryPrecedence

    /// Apply. g § f § a === g(f(a))
    infix operator § : RightApplyPrecedence
    public func §<A, B>(_ f: (A) -> B, _ a: A) -> B {
        return f(a)

    /// Wrapper around operator "as".
    public func cast<A, B>(_ a: A) -> B? {
        return a as? B

  1. And here is our magic - extract the value:

    let temperature = (extract("temperature") § extract("current") § json) ?? NSNotFound

Just one line of code and no force unwraps or manual type casting. This code works in playground, so you can copy and check it. Here is an implementation on GitHub.

@vadian 2016-09-10 07:32:40

First of all never load data synchronously from a remote URL, use always asynchronous methods like URLSession.

'Any' has no subscript members

occurs because the compiler has no idea of what type the intermediate objects are (for example currently in ["currently"]!["temperature"]) and since you are using Foundation collection types like NSDictionary the compiler has no idea at all about the type.

Additionally in Swift 3 it's required to inform the compiler about the type of all subscripted objects.

You have to cast the result of the JSON serialization to the actual type.

This code uses URLSession and exclusively Swift native types

let urlString = ",122.048951"

let url = URL(string: urlString)
URLSession.shared.dataTask(with:url!) { (data, response, error) in
  if error != nil {
  } else {
    do {

      let parsedData = try JSONSerialization.jsonObject(with: data!) as! [String:Any]
      let currentConditions = parsedData["currently"] as! [String:Any]


      let currentTemperatureF = currentConditions["temperature"] as! Double
    } catch let error as NSError {


To print all key / value pairs of currentConditions you could write

 let currentConditions = parsedData["currently"] as! [String:Any]

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

A note regarding jsonObject(with data:

Many (it seems all) tutorials suggest .mutableContainers or .mutableLeaves options which is completely nonsense in Swift. The two options are legacy Objective-C options to assign the result to NSMutable... objects. In Swift any variable is mutable by default and passing any of those options and assigning the result to a let constant has no effect at all. Further most of the implementations are never mutating the deserialized JSON anyway.

The only (rare) option which is useful in Swift is .allowFragments which is required if if the JSON root object could be a value type(String, Number, Bool or null) rather than one of the collection types (array or dictionary). But normally omit the options parameter which means No options.


Some general considerations to parse JSON

JSON is a well-arranged text format. It's very easy to read a JSON string. Read the string carefully. There are only six different types – two collection types and four value types.

The collection types are

  • Array - JSON: objects in square brackets [] - Swift: [Any] but in most cases [[String:Any]]
  • Dictionary - JSON: objects in curly braces {} - Swift: [String:Any]

The value types are

  • String - JSON: any value in double quotes "Foo", even "123"or "false" – Swift: String
  • Number - JSON: numeric values not in double quotes 123 or 123.0 – Swift: Int or Double
  • Bool - JSON: true or false not in double quotes – Swift: true or false
  • null - JSON: null – Swift: NSNull

According to the JSON specification all keys in dictionaries are required to be String.

Basically it's always recommeded to use optional bindings to unwrap optionals safely

If the root object is a dictionary ({}) cast the type to [String:Any]

if let parsedData = try JSONSerialization.jsonObject(with: data!) as? [String:Any] { ...

and retrieve values by keys with (OneOfSupportedJSONTypes is either JSON collection or value type as described above.)

if let foo = parsedData["foo"] as? OneOfSupportedJSONTypes {

If the root object is an array ([]) cast the type to [[String:Any]]

if let parsedData = try JSONSerialization.jsonObject(with: data!) as? [[String:Any]] { ...

and iterate through the array with

for item in parsedData {

If you need an item at specific index check also if the index exists

if let parsedData = try JSONSerialization.jsonObject(with: data!) as? [[String:Any]], parsedData.count > 2,
   let item = parsedData[2] as? OneOfSupportedJSONTypes {

In the rare case that the JSON is simply one of the value types – rather than a collection type – you have to pass the .allowFragments option and cast the result to the appropriate value type for example

if let parsedData = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? String { ...

Apple has published a comprehensive article in the Swift Blog: Working with JSON in Swift

Update: In Swift 4+ the Codable protocol provides a more convenient way to parse JSON directly into structs / classes.

@user2563039 2016-09-10 08:37:27

This is very helpful. I'm just curious why the above code does not show visible output when it's run in a playground.

@vadian 2016-09-10 09:18:36

As mentioned above you need to cast the ambiguous result of dict!["currently"]! to a dictionary that the compiler can safely infer the subsequent key subscription.

@Shades 2016-11-23 00:00:49

The Apple article is pretty cool, but I couldn't get it to run with swift 3 for some reason. It complains about Type [String : Any]? has no subscript members. There was some other issues with it too, but I was able to get around it. Anyone has an example of their code that actually runs?

@vadian 2016-11-23 05:07:43

@Shades Ask a question and post your code. Most likely your issue is related to unwrapped optionals.

@User 2016-12-02 20:39:13

Can you put the sample data that's returned from your API call?

@vadian 2016-12-02 20:46:27

It's not my API, I used the key in the question. Unfortunately the key has expired meanwhile. Feel free to sign in at to get your own key.

@user3286381 2016-12-25 10:17:03

Finally, a solution that works. Thanks. Just a note. For Swift 3 I had to use JSONSerialization.ReadingOptions.mutableContainers rather than the empty array in the options argument. Otherwise, it crashed.

@vadian 2016-12-25 10:21:11

@user3286381 .mutableContainers is completely useless in Swift with native collection types. The crash might be related to somewhere else.

@Dan Rosenstark 2017-03-30 22:19:40

both forcing the unwrap to [String:Any] or doing an optional bind (as Apple does in the link you provided) make no sense. All this optionality is insane. Nice answer, though, thanks!

@MCCCS 2017-05-20 11:45:17

Why is connecting asynchronously so important?

@SaschaM78 2017-12-30 09:40:02

@MCCCS a synchronous call will block the caller (=app) until the response is received, resulting in an apparently hanging application.

@Robert Dundon 2018-04-09 16:15:39

Thanks for the note about mutableContainers A tutorial mentioned it, but did not mentioned WHY (at least from what I recall). Good to know its intention and that it's not needed.

@David Siegel 2017-10-14 05:08:13

I built quicktype exactly for this purpose. Just paste your sample JSON and quicktype generates this type hierarchy for your API data:

struct Forecast {
    let hourly: Hourly
    let daily: Daily
    let currently: Currently
    let flags: Flags
    let longitude: Double
    let latitude: Double
    let offset: Int
    let timezone: String

struct Hourly {
    let icon: String
    let data: [Currently]
    let summary: String

struct Daily {
    let icon: String
    let data: [Datum]
    let summary: String

struct Datum {
    let precipIntensityMax: Double
    let apparentTemperatureMinTime: Int
    let apparentTemperatureLowTime: Int
    let apparentTemperatureHighTime: Int
    let apparentTemperatureHigh: Double
    let apparentTemperatureLow: Double
    let apparentTemperatureMaxTime: Int
    let apparentTemperatureMax: Double
    let apparentTemperatureMin: Double
    let icon: String
    let dewPoint: Double
    let cloudCover: Double
    let humidity: Double
    let ozone: Double
    let moonPhase: Double
    let precipIntensity: Double
    let temperatureHigh: Double
    let pressure: Double
    let precipProbability: Double
    let precipIntensityMaxTime: Int
    let precipType: String?
    let sunriseTime: Int
    let summary: String
    let sunsetTime: Int
    let temperatureMax: Double
    let time: Int
    let temperatureLow: Double
    let temperatureHighTime: Int
    let temperatureLowTime: Int
    let temperatureMin: Double
    let temperatureMaxTime: Int
    let temperatureMinTime: Int
    let uvIndexTime: Int
    let windGust: Double
    let uvIndex: Int
    let windBearing: Int
    let windGustTime: Int
    let windSpeed: Double

struct Currently {
    let precipProbability: Double
    let humidity: Double
    let cloudCover: Double
    let apparentTemperature: Double
    let dewPoint: Double
    let ozone: Double
    let icon: String
    let precipIntensity: Double
    let temperature: Double
    let pressure: Double
    let precipType: String?
    let summary: String
    let uvIndex: Int
    let windGust: Double
    let time: Int
    let windBearing: Int
    let windSpeed: Double

struct Flags {
    let sources: [String]
    let isdStations: [String]
    let units: String

It also generates dependency-free marshaling code to coax the return value of JSONSerialization.jsonObject into a Forecast, including a convenience constructor that takes a JSON string so you can quickly parse a strongly typed Forecast value and access its fields:

let forecast = Forecast.from(json: jsonString)!

You can install quicktype from npm with npm i -g quicktype or use the web UI to get the complete generated code to paste into your playground.

@drew.. 2017-12-30 22:15:53

The links are failing.

@David Siegel 2017-12-30 22:16:41

Oops! That's –– fixing now.

@marko 2018-04-29 06:47:08

Fantastic time saver! Good job!

@Ahmet Ardal 2018-11-17 20:17:15

Brilliant tool. Thanks.

@Arun K 2017-10-27 14:16:00

The Problem is with the API interaction method.The JSON parsing is changed only in Syntax. The main problem is with the way of fetching data. What you are using is a synchronous way of getting data. This doesn't work in every case. What you should be using is an asynchronous way to Fetch data. In this way, you have to request data through the API and wait for it to respond with data. You can achieve this with URL session and third-party libraries like Alamofire. Below is the Code for URL Session method.

let urlString = ",122.048951"

let url = URL.init(string: urlString)
URLSession.shared.dataTask(with:url!) { (data, response, error) in
  guard error == nil else {
  do {

    let Data = try JSONSerialization.jsonObject(with: data!) as! [String:Any] // Note if your data is coming in Array you should be using [Any]()
    //Now your data is parsed in Data variable and you can use it normally

    let currentConditions = Data["currently"] as! [String:Any]


    let currentTemperatureF = currentConditions["temperature"] as! Double
  } catch let error as NSError {



@Marco Weber 2017-01-05 11:37:10

Updated the isConnectToNetwork-Function afterwards, thanks to this post Check for internet connection with Swift

i wrote an extra method for it:

import SystemConfiguration

func loadingJSON(_ link:String, postString:String, completionHandler: @escaping (_ JSONObject: AnyObject) -> ()) {
    if(isConnectedToNetwork() == false){
       completionHandler("-1" as AnyObject)

    let request = NSMutableURLRequest(url: URL(string: link)!)
    request.httpMethod = "POST"
    request.httpBody = String.Encoding.utf8)

    let task = URLSession.shared.dataTask(with: request as URLRequest) { data, response, error in
    guard error == nil && data != nil else {                                                          // check for fundamental networking error

    if let httpStatus = response as? HTTPURLResponse , httpStatus.statusCode != 200 {           // check for http errors
        print("statusCode should be 200, but is \(httpStatus.statusCode)")
        print("response = \(response)")

    //JSON successfull
    do {

        let parseJSON = try JSONSerialization.jsonObject(with: data!, options: .allowFragments)

        DispatchQueue.main.async(execute: {
            completionHandler(parseJSON as AnyObject)

    } catch let error as NSError {
        print("Failed to load: \(error.localizedDescription)")


func isConnectedToNetwork() -> Bool {

    var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
    zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
    zeroAddress.sin_family = sa_family_t(AF_INET)

    let defaultRouteReachability = withUnsafePointer(to: &zeroAddress) {
        $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {zeroSockAddress in
            SCNetworkReachabilityCreateWithAddress(nil, zeroSockAddress)

    var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags(rawValue: 0)
    if SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) == false {
        return false

    let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
    let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
    let ret = (isReachable && !needsConnection)

    return ret


So now you can easily call this in your app wherever you want

loadingJSON("", postString:"email=\(userEmail!)&password=\(password!)") {
            parseJSON in

            if(String(describing: parseJSON) == "-1"){
                print("No Internet")
            } else {

                if let loginSuccessfull = parseJSON["loginSuccessfull"] as? Bool {
                    //... do stuff

@KamalPanhwar 2017-01-24 19:38:29

Marco, what would be best way to add this function in project? in any contorller or model?

@Marco Weber 2017-02-07 11:32:12

hey, you just add the first method func loadingJSON(...) in an extra swift file or class. After that you are able to call this from every controller in your project

@Amr Angry 2017-02-16 07:51:41

i did try it , but i love the idea of demonstrating a full solution and also how to use it including the helper method isConnectedToNetwork() it me the idea of how to implement it probably in good code

@Marco Weber 2017-02-17 09:26:32

so i just used a new swift-file (left klick on your project tree, new file ..., swift file) and called it jsonhelper.swift. in this file you place the first code, loadingJSON() and isConnectedToNetwork(). after that you can use this two functions in every part of your project. for example in a loginVC, as an action of the login button you're able to use the second code, obviously you have to change the domain, the post string and the paseJson values (parseJSON["loginSuccessfull"]) so they match to your php file

@BhuShan PaWar 2017-01-24 05:19:51

let str = "{\"names\": [\"Bob\", \"Tim\", \"Tina\"]}"

let data = String.Encoding.utf8, allowLossyConversion: false)!

do {
    let json = try JSONSerialization.jsonObject(with: data, options: []) as! [String: AnyObject]
    if let names = json["names"] as? [String] 
} catch let error as NSError {
    print("Failed to load: \(error.localizedDescription)")

@discorevilo 2016-09-10 07:34:27

A big change that happened with Xcode 8 Beta 6 for Swift 3 was that id now imports as Any rather than AnyObject.

This means that parsedData is returned as a dictionary of most likely with the type [Any:Any]. Without using a debugger I could not tell you exactly what your cast to NSDictionary will do but the error you are seeing is because dict!["currently"]! has type Any

So, how do you solve this? From the way you've referenced it, I assume dict!["currently"]! is a dictionary and so you have many options:

First you could do something like this:

let currentConditionsDictionary: [String: AnyObject] = dict!["currently"]! as! [String: AnyObject]  

This will give you a dictionary object that you can then query for values and so you can get your temperature like this:

let currentTemperatureF = currentConditionsDictionary["temperature"] as! Double

Or if you would prefer you can do it in line:

let currentTemperatureF = (dict!["currently"]! as! [String: AnyObject])["temperature"]! as! Double

Hopefully this helps, I'm afraid I have not had time to write a sample app to test it.

One final note: the easiest thing to do, might be to simply cast the JSON payload into [String: AnyObject] right at the start.

let parsedData = try JSONSerialization.jsonObject(with: data as Data, options: .allowFragments) as! Dictionary<String, AnyObject>

@vadian 2016-09-10 07:40:38

dict!["currently"]! as! [String: String] will crash

@discorevilo 2016-09-10 07:55:46

The point at which it crashed was the ["temperature"]!! and also trying to cast String to NSString - verified the new solution works

@vadian 2016-09-10 07:59:48

[String: String] cannot work at all because there are a couple of numeric values. It doesn't work in a Mac Playground

@discorevilo 2016-09-10 08:10:31

@vadian ah, yes I had not noticed those and the swift sandbox helpfully hid them! - Corrected [once again] now (and tested on macOS). Thank you for pointing this out :)

Related Questions

Sponsored Content

29 Answered Questions

[SOLVED] How Do You Parse and Process HTML/XML in PHP?

33 Answered Questions

[SOLVED] What is the correct JSON content type?

25 Answered Questions

[SOLVED] How do I parse a string to a float or int in Python?

46 Answered Questions

[SOLVED] Can comments be used in JSON?

  • 2008-10-28 20:39:03
  • Michael Gundlach
  • 1647698 View
  • 6263 Score
  • 46 Answer
  • Tags:   json comments

53 Answered Questions

[SOLVED] How can I pretty-print JSON in a shell script?

9 Answered Questions

[SOLVED] Parsing values from a JSON file?

  • 2010-05-14 15:54:20
  • michele
  • 2403501 View
  • 1327 Score
  • 9 Answer
  • Tags:   python json parsing

6 Answered Questions

[SOLVED] Why does Google prepend while(1); to their JSON responses?

31 Answered Questions

[SOLVED] How to parse JSON in Java

  • 2010-04-07 09:00:21
  • Muhammad Maqsoodur Rehman
  • 1335330 View
  • 862 Score
  • 31 Answer
  • Tags:   java json parsing

39 Answered Questions

[SOLVED] How do I format a Microsoft JSON date?

16 Answered Questions

[SOLVED] Parse JSON in JavaScript?

Sponsored Content