如何解析这个复杂的嵌套 Json

how to parse this complex nested Json

Json 是有效的,但我用下面的代码和返回的结构得到 nil json。

遇到的问题:

  1. at JSonDecoder.decode() :它返回了这个错误消息:

    keyNotFound(CodingKeys(stringValue: "items", intValue: nil), Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "items", intValue: nil), _JSONKey(stringValue: "Index 0" , intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: "items", intValue: nil) ("items").", underlyingError: nil))

  2. 如何从 Json

    获取这些 a) 图片 b) 位置

谢谢

这里是代码

func getJsonMapData(){
        
        guard let mapUrl = URL(string: "https://xxxxxx/traffic-images") else { return }
        
        URLSession.shared.dataTask(with: mapUrl) { (data, response, error) in
        
            guard error == nil else { return}

            guard let data = data else { return}
         
            //- problem: 

            do {

                let LocationArrDict = try JSONDecoder().decode([String:[Location]].self, from: data)else{
                
                print(LocationArrDict)              
  
            } catch {

              print(error)
            }
           
        }.resume()
    }



//------------- return Json String:

{
   "items":[
      {
         "timestamp":"2020-12-05T08:45:43+08:00",
         "cameras":[
            {
               "timestamp":"2020-11-05T08:42:43+08:00",
               "image":"https://xxxxxxxxx/traffic-images/2020/12/2ab06cd8-4dcf-434c-b758-804e690e57db.jpg",
               "location":{
                  "latitude":1.29531332,
                  "longitude":103.871146
               },
               "camera_id":"1001",
               "image_metadata":{
                  "height":240,
                  "width":320,
                  "md5":"c9686a013f3a2ed4af61260811661fc4"
               }
            },
            {
               "timestamp":"2020-11-05T08:42:43+08:00",
               "image":"https://xxxxxxxxxx/traffic-images/2020/12/9f6d307e-8b05-414d-b27d-bf1414aa2cc7.jpg",
               "location":{
                  "latitude":1.319541067,
                  "longitude":103.8785627
               },
               "camera_id":"1002",
               "image_metadata":{
                  "height":240,
                  "width":320,
                  "md5":"78060d8fbdd241adf43a2f1ae5d252b1"
               }
             },

                    ........

            {
               "timestamp":"2020-12-05T08:42:43+08:00",
               "image":"https://xxxxxx/traffic-images/2020/12/98f64fe6-5985-4a8a-852f-0be24b0a6271.jpg",
               "location":{
                  "latitude":1.41270056,
                  "longitude":103.80642712
                },
                 "camera_id":"9706",
                 "image_metadata":{
                  "height":360,
                  "width":640,
                  "md5":"f63d54176620fa1d9896fa438b3cc753"
                }
            }
          ]
        }
  
       ],
  
      "api_info":{
         "status":"healthy"
       }
}



//------------ struct for the return Json result:


// MARK: - Location

struct Location: Codable {
    let items: [Item]
    let apiInfo: APIInfo

    enum CodingKeys: String, CodingKey {
        case items
        case apiInfo = "api_info"
    }
}

// MARK: - APIInfo
struct APIInfo: Codable {
    let status: String
}

// MARK: - Item
struct Item: Codable {
    let timestamp: Date
    let cameras: [Camera]
}

// MARK: - Camera
struct Camera: Codable {
    let timestamp: Date
    let image: String
    let location: LocationClass
    let cameraID: String
    let imageMetadata: ImageMetadata

    enum CodingKeys: String, CodingKey {
        case timestamp, image, location
        case cameraID = "camera_id"
        case imageMetadata = "image_metadata"
    }
}

// MARK: - ImageMetadata
struct ImageMetadata: Codable {
    let height, width: Int
    let md5: String
}

// MARK: - LocationClass
struct LocationClass: Codable {
    let latitude, longitude: Double
}



``

错误 #1:要解码的类型错误,必须是 Location.self
错误 #2:要将 ISO 日期解码为 Date,您必须添加 .iso8601 日期解码策略。

do {
    let decoder = JSONDecoder()
    decoder.dateDecodingStrategy = .iso8601
    let locationArrDict = try decoder.decode(Location.self, from: data)
    print(locationArrDict)              

} catch {
   print(error)
}

并且您可以将表示 URL 的字符串直接解码为 URL

您必须创建数据模型并将它们描述为您期望收到的响应。我将根据您的 json 解码方式给您一个简短的示例。

首先,为了使用 JSONDecoder 解码 JSON,您的模型必须符合 Decodable 协议。然后你必须创建这些模型。

struct Item: Decodable {
    let timestamp: Date
//    let cameras: [...]
}

struct ApiInfo: Decodable {
    enum Status: String, Decodable {
        case healthy
    }
    
    let status: Status
}

struct Response: Decodable {
    let items: [Item]
    let apiInfo: ApiInfo
}

然后您必须配置 JSONDecoder 并解码 JSON。我们可以清楚地看到,您的 JSON 使用 snake_case 命名约定,这不是 JSONDecoder 的默认命名约定,因此您必须对其进行设置。同样也适用于日期 - 它使用 iso8601 表示标准。

let jsonDecoder = JSONDecoder()
jsonDecoder.dateDecodingStrategy = .iso8601
jsonDecoder.keyDecodingStrategy = .convertFromSnakeCase

终于给你解码了

do {
    let response = try jsonDecoder.decode(Response.self, from: jsonData)
    print(response)
} catch {
    print(error)
}