【问题标题】:Swift - Decoding a Deeply Nested DictionarySwift - 解码深度嵌套的字典
【发布时间】:2018-12-12 21:37:48
【问题描述】:

我是如此接近 - 但我正在努力使用一个非常简单的函数来访问深深嵌套在我的 JSON 中的数据点。我使用的示例是在 Google 路线 API 上。

JSON 示例(来自 GMapsAPI):

{
  "geocoded_waypoints" : [
  {
     "geocoder_status" : "OK",
     "partial_match" : true,
     "place_id" : "ChIJ960bMolw44kRQcGOlOZQ-r8",
     "types" : [ "premise" ]
  },
  {
     "geocoder_status" : "OK",
     "partial_match" : true,
     "place_id" : "EiMxMTggU2FsZW0gU3QsIEJvc3RvbiwgTUEgMDIxMTMsIFVTQSIaEhgKFAoSCSvDfDSJcOOJEbQanF0WxROfEHY",
     "types" : [ "street_address" ]
  }
],
"routes" : [
  {
     "bounds" : {
        "northeast" : {
           "lat" : 42.3647252,
           "lng" : -71.0555085
        },
        "southwest" : {
           "lat" : 42.3644965,
           "lng" : -71.05552419999999
        }
     },
     "copyrights" : "Map data ©2018 Google",
     "legs" : [
        {
           "distance" : {
              "text" : "82 ft",
              "value" : 25
           },
           "duration" : {
              "text" : "1 min",
              "value" : 11
           },
           "end_address" : "118 Salem St, Boston, MA 02113, USA",
           "end_location" : {
              "lat" : 42.3647252,
              "lng" : -71.0555085
           },
           "start_address" : "115 Salem St, Boston, MA 02113, USA",
           "start_location" : {
              "lat" : 42.3644965,
              "lng" : -71.05552419999999
           },
           "steps" : [
              {
                 "distance" : {
                    "text" : "82 ft",
                    "value" : 25
                 },
                 "duration" : {
                    "text" : "1 min",
                    "value" : 11
                 },
                 "end_location" : {
                    "lat" : 42.3647252,
                    "lng" : -71.0555085
                 },
                 "html_instructions" : "Head \u003cb\u003enorth\u003c/b\u003e on \u003cb\u003eSalem St\u003c/b\u003e toward \u003cb\u003eJerusalem Pl\u003c/b\u003e",
                 "polyline" : {
                    "points" : "ciqaG~_upLO?]A"
                 },
                 "start_location" : {
                    "lat" : 42.3644965,
                    "lng" : -71.05552419999999
                 },
                 "travel_mode" : "DRIVING"
              }
           ],
           "traffic_speed_entry" : [],
           "via_waypoint" : []
        }
     ],
     "overview_polyline" : {
        "points" : "ciqaG~_upLm@A"
     },
     "summary" : "Salem St",
     "warnings" : [],
     "waypoint_order" : []
  }
  ],
"status" : "OK"
}

可解码结构:为了解决这个问题,我使用了可解码结构。我已经能够访问第一级嵌套数据(routes.summary),但我正在努力进一步下降(例如:routes.legs.duration)。我的代码结构如下:

struct Directions: Decodable {
    let status: String
    let routes: [Routes]

         enum CodingKeys :String, CodingKey {
              case status, routes
    }

struct Routes: Decodable {
    let summary: String
    let legs: [Legs]

         enum CodingKeys : String, CodingKey {
              case summary, legs
          }
}

struct Legs: Decodable {
    let duration: Duration

          enum CodingKeys : String, CodingKey {
          case duration
          }
    }

struct Duration: Decodable {
        let text: String    

            enum CodingKeys : String, CodingKey {
               case text
            }
        }

URL 设置后的实施

      URLSession.shared.dataTask(with: url) { (data, response, err) in
          guard let data = data else { return }
          do {   
             let directions = try
             JSONDecoder().decode(Directions.self, from: data)

        for item in directions.routes {
            self.stringoutput = item.summary          
       }

毕竟,我想做的就是能够访问 JSON 中的“文本”并返回该值。代码的最后一行能够成功返回 JSON 中的“summary”;我可以打印(方向),整个数组/字典将返回调试区域,包括“文本”。但我还是不知道该怎么做:

x = direction.routes.legs.duration.text

使 x 等于“1 分钟”

感谢任何人的帮助。

编辑:最终起作用的是下面的 Vadian 结构键和以下 for in 循环:

                for item in directions.routes {
                    print(item.summary)
                    self.direct = item.summary
                    for items in item.legs {
                        self.stringoutput = items.duration.text
                        print(items.duration.text)
                        }

干杯!

【问题讨论】:

  • trimed it down 和这种难以理解的结构混乱一样没有帮助。请正确格式化代码并删除不必要的空行。
  • 感谢您对代码格式的反馈并更新了 JSON。进行了一些更新,希望使其更具可读性 - 为新手错误道歉。
  • 在你的 for 循环中做 x = item.duration.text 是否有效?
  • 这个x = directions.routes.legs.duration.text 不能工作,因为Legs 是一个数组。所以你将不得不做这样的事情x = directions.routes.legs[0].duration.text
  • 我建议您将您正在寻求帮助的整个 JSON 放在那里。如果你有一个端点,你可以公开它来回退 JSON,我个人更喜欢这样,因为我可以将它转储到 Postman 中,然后亲眼看看会返回什么。

标签: swift google-maps directions decodable


【解决方案1】:

这些结构不会解码所有键,但它是一个起点。

如果键和结构成员同名,则无需指定CodingKeys

struct Directions: Decodable {
    let status: String
    let routes: [Route]
}

struct Route: Decodable {
    let summary: String
    let legs: [Leg]
}

struct Leg: Decodable {
    let duration : TextValue
    let distance : TextValue
    let endAddress : String
    let endLocation : Location
    let startAddress : String
    let startLocation : Location
    let steps : [Step]
}

struct TextValue: Decodable {
    let text: String
    let value : Int
}

struct Location: Decodable {
    let lat, lng : Double
}

struct Step: Decodable {
    let duration : TextValue
    let distance : TextValue
    let endLocation : Location
    let startLocation : Location
    let htmlInstructions : String
    let travelMode : String
}

要正确解码 snake_cased 密钥,您必须添加适当的密钥解码策略

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase

要访问数组 ([]),您必须按索引获取项目

step[0]

或用循环迭代数组

for step in steps {}

【讨论】:

  • 瓦迪安,感谢您的帮助。我最终使用了您的代码,对我有用的是我编辑的主帖子中的 for in 循环。谢谢!
猜你喜欢
  • 1970-01-01
  • 2014-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-17
  • 1970-01-01
  • 2021-12-29
  • 2022-01-24
相关资源
最近更新 更多