0

How can I get the third-level values from this JSON data?

{
  "data": [
    {
      "id": "1669690663119337",
      "name": "Event1",
      "attending_count": 17,
      "cover": {
        "offset_x": 0,
        "offset_y": 50,
        "source": "https://imageurl",
        "id": "1769679396399074"
      }
    },
    {
      "id": "130418660933615",
      "name": "Event2",
      "attending_count": 923,
      "cover": {
        "offset_x": 0,
        "offset_y": 50,
        "source": "https://imageurl",
        "id": "10156609677937586"
      }
    },
    {
      "id": "1883372648594017",
      "name": "Event3",
      "attending_count": 1695,
      "cover": {
        "offset_x": 0,
        "offset_y": 50,
        "source": "imageurl",
        "id": "10156575272607586"
      }
    }

For second-level values (id,name,attending_count), im using these lines of code:

struct JsonFromWeb: Codable {
    let data: [Course]
}

struct Course: Codable {
    let id: String?
    let name: String?
    let attending_count: Int?
}


class JsonViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    @IBOutlet var eventTable: UITableView!

    var event = [Course]()

    override func viewDidLoad() {
        super.viewDidLoad()
            let jsonUrlString = "https://www.jsonurl.url/"
            guard let url = URL(string: jsonUrlString) else { return }
            print(jsonUrlString)
            URLSession.shared.dataTask(with: url) { (data, response, err) in
                guard let data = data else { return }
                do {
                    let courses = try JSONDecoder().decode(JsonFromWeb.self, from: data)
                    self.event = courses.data
                    DispatchQueue.main.async {
                        self.eventTable.reloadData()
                    }
                } catch let jsonErr {
                    print("Error jsonErr", jsonErr)
                }
                }.resume()
        }

    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return event.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "eventCell") as? UserEventsTableViewCell else { return UITableViewCell() }
        cell.nameLabel.text = event[indexPath.row].name
        return cell
    }
}
0

1 Answer 1

1

It's exactly the same pattern as for the second level. You have to create a separate struct / class for any dictionary. The name of the struct is arbitrary. The property in the parent struct / class must match the dictionary key (in this case cover)

struct JsonFromWeb: Codable {
    let data: [Course]
}

struct Course: Codable {

    private enum CodingKeys : String, CodingKey {
        case attendingCount = "attending_count"
        case id, name, cover
    }
    let id: String
    let name: String
    let attendingCount: Int
    let cover: Cover
}    

struct Cover : Codable {

    private enum CodingKeys : String, CodingKey {
        case offsetX = "offset_x"
        case offsetY = "offset_y"
        case source, id
    }
    let offsetX: Int
    let offsetY: Int
    let source: String
    let id: String
}

Note:

Never use this syntax

guard let cell = tableView.dequeueReusableCell(withIdentifier: "eventCell") as? UserEventsTableViewCell else { 
    return UITableViewCell() 
}

This is one of the few cases where force unwrapping is recommended to discover design errors. If everything is hooked up correctly the code must not crash. And use the dequeue API which returns always a valid cell:

let cell = tableView.dequeueReusableCell(withIdentifier: "eventCell", for: indexPath) as! UserEventsTableViewCell
Sign up to request clarification or add additional context in comments.

5 Comments

First, thank you very much for answering so quickly. But can you help me also adding this "source" variable to table, like i added "name" variable? That would make my day :) Using this: let courses = try JSONDecoder().decode(JsonFromWeb.self, from: data) self.event = courses.data
What is the problem? Your code is supposed to work. If no data are displayed the error is related to the custom table view cell
When i replace my part of code with your code, then error appears: (CodingKeys in _BD6BE31D58877246570CAEB111C1E2ED).data, Foundation.(_JSONKey in _12768CA107A31EF2DCE034FD75B541C9)(stringValue: "Index 17", intValue: Optional(17))], debugDescription: "No value associated with key cover (\"cover\").", underlyingError: nil)) And i should not use this with variables? : cell.nameLabel.text = event[indexPath.row].name
If cover can be nil than make cover optional: let cover: Cover?
Yes, now it works. Thank you again, you helped me alot! :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.