【问题标题】:how to parse this complex nested Json如何解析这个复杂的嵌套 Json
【发布时间】:2021-03-17 03:04:01
【问题描述】:

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

遇到的问题:

  1. 在 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
}



``

【问题讨论】:

  • 不要在 Codable 环境中使用 try?,永远不要 try? 忽略错误。 捕捉错误并打印出来。至少有两个。
  • 您发布的 JSON 似乎无效。括号不平衡。
  • @Sweeper,json 结果太长,无法在此处显示。我检查了在线 json 验证器。我尝试 [Location].self、[String: [Location]].self 或 Location.self,它们不起作用。
  • 你应该显示一个minimal reproducible example,不管实际的JSON是否太长。显示重现问题的最短、有效 JSON。
  • @Swepeer,查看更新。 json 结果如上所示。问题已在代码部分指出。

标签: json swift swift4.2 jsondecoder


【解决方案1】:

错误#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

【讨论】:

  • 让我使用您的解决方案并尽快返回这里。使用您发布的代码后,我似乎出错了-> TypeMismatch(swift.double, Swift.decoding error.Context...... "expectedto decode Double but foundastring/dat instead"
  • 你真的使用带有日期解码策略的解码器实例吗?错误表明你没有。
  • 您的解决方案有效。不想一口气问这么多问题。我认为我的解析 json 需要很多帮助才能学习。我认为这个练习会提高我对 json 的理解。我有 2 个关于 Json 的问题。感谢您的帮助:stackoverflow.com/questions/65157052/…
  • 抱歉,我不熟悉 Google Maps API
【解决方案2】:

您必须创建数据模型并将它们描述为您期望收到的响应。我将根据您的 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)
}

【讨论】:

    猜你喜欢
    • 2021-09-23
    • 1970-01-01
    • 1970-01-01
    • 2016-01-28
    • 2019-08-28
    • 1970-01-01
    • 2017-05-21
    • 2019-06-11
    • 1970-01-01
    相关资源
    最近更新 更多