Working with structures

This is the response that I get from an API call. I wanted to decode the JSON data that I receive. How do I go about with the structure "list" in the response?

1 Like

The standard way of doing this is to declare structs that match your JSON and make them Codable. The compiler then deals with all the details required to encode and decode the JSON. There’s tonnes of info about this out there on the ’net, but as an Apple person I’m going to point you to Apple resources (-:

To make this concrete, here’s some test code inspired by your example:

let json = """
    {
        "total": 1,
        "list": [
            {
                "lockId": 12345
            },
            {
                "lockId": 54321
            }
        ]
    }
    """

struct Response: Codable {
    var total: Int
    var list: [ListElement]
}

struct ListElement: Codable {
    var lockId: Int
}

let jsonData = Data(json.utf8)
let response = try JSONDecoder().decode(Response.self, from: jsonData)
print(response.list[1].lockId)  // -> 54321

ps It helps if you post the text of your data rather than a screen shot; that way folks can copy’n’paste it into a test project.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

3 Likes

Thank you so much for you reply. And the resource links. Will check them out :slight_smile:

struct locks: Codable {
  var list : [lists]
  let pageNo : Int
  let pageSize: Int
  let pages: Int
  let total : Int
}

struct lists: Codable {
  let lockId : Int
  let date : Int
  let lockName : String
  let lockAlias : String
  let lockMac : String
  let electricQunatity : Int
  let keyboardPwdVersion : Int
  let specialValue : Int
}
 let dataAsString = String(data: data!, encoding: String.Encoding.utf8)
 print(dataAsString!)       

 let users = try? JSONDecoder().decode(locks.self, from: data!)
 print(users)

Here, data is the URL data that I receive.
This is the output that I am receiving.
The nil value is when I print "users" and the list is the value of "dataAsString"

{"list":[{"lockId":1272137,"date":1553078256000,"specialValue":21731,"electricQuantity":15,"lockAlias":"A","keyboardPwdVersion":4,"lockMac":"E9:45:BA:7B:ED:28","lockName":"S202C_28ed7b"}],"pageNo":1,"pageSize":10000,"pages":1,"total":1}  nil

Try this

do {
    let users = try JSONDecoder().decode(locks.self, from: data!)
    print(users)
} catch {
    print(error)
}

You will get

keyNotFound(CodingKeys(stringValue: "electricQunatity", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "list", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: \"electricQunatity\", intValue: nil) (\"electricQunatity\").", underlyingError: nil))
struct list: Codable {
   let electricQunatity : Int  // but your data is {"electricQuantity":15}
}
1 Like

Hi,

Instead of:

Write instead:

do {
    let users = try JSONDecoder().decode(locks.self, from: data!)
    print(users)
} catch {
    print(error)
}

Run it: it will print an error message. Read this error message carefully, because it tells what is wrong. It will help you fix the error.

Generally speaking, avoid try? when you are debugging some code, because try? hides errors away, and just give you back a plain nil which does not tell you what has turned wrong. Instead, use try, catch errors, and look at them, because this is generally where the solution is.

We had the same idea :-)

2 Likes

Thank you! This worked!

1 Like

Seems like you got this working. Yay!

One follow-up point regarding this:

struct locks: Codable {
    …
}

struct lists: Codable {
    …
}

In Swift we generally start types with an uppercase letter. So locks would become Locks, and so on.

If you’re curious about the details here, check out the Swift API Design Guidelines.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

2 Likes