将 JSON 响应解析为结构

Posted

技术标签:

【中文标题】将 JSON 响应解析为结构【英文标题】:Parsing JSON response into a struct 【发布时间】:2019-05-29 19:06:08 【问题描述】:

我正在使用 Alamofire 并以 JSON 格式从 API 取回数据。 我想将数据用于结构。 响应如下:


  "status" : 1,
  "data" : [

  "classes" : [

  ],
  "day" : "Wednesday"
,

  "classes" : [
    
      "time" : "1:30 PM",
      "available_spots" : 2,
      "trainer" : "Ahmed Jasim",
      "thumbnail" : "\/uploads\/classes\/6\/files\/class_6_15555066955cb72607131886.71740331.jpg",
      "id" : 6,
      "name" : "Gym Class C"
    
  ],
  "day" : "Thursday"
,

  "classes" : [

  ],
  "day" : "Friday"
,

  "classes" : [

  ],
  "day" : "Saturday"
,

  "classes" : [
    
      "available_spots" : 2,
      "id" : 1,
      "trainer" : "Ahmed Jasim",
      "name" : "Karate",
      "thumbnail" : "\/uploads\/classes\/1\/files\/class_1_15548800215cad9615e62404.41767774.jpg",
      "time" : "5:00 PM"
    
  ],
  "day" : "Sunday"
,

  "classes" : [
    
      "thumbnail" : "\/uploads\/classes\/1\/files\/class_1_15548800215cad9615e62404.41767774.jpg",
      "available_spots" : 2,
      "time" : "11:00 AM",
      "name" : "Karate",
      "id" : 1,
      "trainer" : "Ahmed Jasim"
    ,
    
      "trainer" : "Jalal Hassan",
      "available_spots" : 20,
      "thumbnail" : "\/uploads\/classes\/2\/files\/class_2_15548819805cad9dbc7b9a80.11639647.jpg",
      "time" : "4:00 PM",
      "name" : "Gym Class B",
      "id" : 2
    
  ],
  "day" : "Monday"
,

  "classes" : [
    
      "name" : "Gym Class B",
      "trainer" : "Jalal Hassan",
      "time" : "9:00 AM",
      "available_spots" : 20,
      "id" : 2,
      "thumbnail" : "\/uploads\/classes\/2\/files\/class_2_15548819805cad9dbc7b9a80.11639647.jpg"
    
  ],
  "day" : "Tuesday"

 ],
 "message" : "Retrieved successfully",
 "success" : true

我想获取“day & classes”并在结构中使用它们。 我使用的结构如下。

struct section 
day: String!
classes: [String]! 

所以我想得到一天和它的类并存储它们。 对结构的调用:

 var sections = [Section(day: "Monday", classes: ["A","B","C"]]

我想要实现的是得到所有的日子和它的类 & 如果一天没有类它只是一个空数组。

但我不确定这是否可能。

这是 Alamofire 请求中的代码:

     let classesJSON: JSON = JSON(response.result.value!)


                if response.data != nil 

                    for index in 0..<classesJSON["data"].count 

                        var sections = Section(day: classesJSON["data"][index]["day"].stringValue, classes: [])
                        for data in classesJSON["data"].arrayValue 

                            for value in data["classes"].arrayValue 
                                sections.classes.append(value["name"].stringValue)
                               //sections.classes[index] = value["name"].stringValue
                            
                        
                        print(sections)
                    

                

我的问题是我得到了响应中的所有课程,我想要的是获得当天的特定课程。

Section(day: Optional("Sunday"), classes: Optional(["Gym Class C", "Karate", "Karate", "Gym Class B", "Gym Class B"])

Section(day: Optional("Monday"), classes: Optional(["Gym Class C", "Karate", "Karate", "Gym Class B", "Gym Class B"])

^这是我得到的,但我想把它们分开,这样我就可以得到一天和它的课程,而不是全部

【问题讨论】:

如果你想将 JSON 解析成结构(一个是不够的)SwiftyJSON 是不合适的。使用Codable。相关问题数不胜数。 【参考方案1】:

我建议放弃 SwiftyJSON 并使用带有 Codable 的真实模型对象。

使用以下结构解析数据:

struct APIResponse: Codable 
    let status: Int
    let data: [ClassData]
    let message: String
    let success: Bool


struct ClassData: Codable 
    let classes: [Class]
    let day: String


struct Class: Codable 
    let time: String
    let availableSpots: Int
    let trainer, thumbnail: String
    let id: Int
    let name: String

    enum CodingKeys: String, CodingKey 
        case time
        case availableSpots = "available_spots"
        case trainer, thumbnail, id, name
    


struct Section 
    let day: String
    let classes: [String]


do 
    let response = try JSONDecoder().decode(APIResponse.self, from: json)

    let classesPerDay: [String: [Class]] = response.data.reduce(into: [:]) 
        $0[$1.day, default: []].append(contentsOf: $1.classes)
    

    let sections = classesPerDay.map  Section(day: $0, classes: $1.map  $0.name ) 
    print(sections)
 catch 
    print(error)

【讨论】:

【参考方案2】:

你可以稍微改变你的循环

for index in 0..<classesJSON["data"].count 
    var classes: [String] = []
    for item in classesJSON["data"][index]["classes"].arrayValue 
          classes.append(item["name"].stringValue)
    
    let sections = Section(day: classesJSON["data"][index]["day"].stringValue, classes: classes)
    print(sections)
 

并确保将结构中的日期和课程的 let 更改为 var

struct Section 
    var day: String
    var classes: [String]

【讨论】:

以上是关于将 JSON 响应解析为结构的主要内容,如果未能解决你的问题,请参考以下文章

快速解析动态键的json响应问题

将 alamofire 响应解析为 JSON 返回 nil

将 JSON 响应解析为对象

将来自 websocket 消息的字符串响应解析为 JSON

将 JSON 解析为结构

JSON 解析,嵌套 JSON 结构的问题