使用 JSON 解码器解压嵌套的 JSON 值

Use JSONDecoder to unpack nested JSON values

如何从此 JSON 数据中获取三级值?

{
  "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"
      }
    }

对于二级值(id,name,attending_count),我使用这些代码行:

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
    }
}

和第二关的模式完全一样。您必须为任何字典创建一个单独的 struct / class 。结构的名称是任意的。父结构中的 属性 / class 必须匹配字典键(在本例中为 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
}

注:

从不 使用此语法

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

这是为数不多的建议强制展开以发现设计错误的案例之一。如果一切都正确连接,代码 一定不会 崩溃。并使用 dequeue API 其中 returns 始终是一个有效的单元格:

let cell = tableView.dequeueReusableCell(withIdentifier: "eventCell", for: indexPath) as! UserEventsTableViewCell