首页 > 解决方案 > Swift 4 解析嵌套的 JSON 数组,这是来自 Web 服务的响应

问题描述

这是我的 JSON,它是来自 Web 服务的响应,

{
"Data": [
    {
        "Id": 181670,
        "PatientId": 10086,
        "Form": "{\"Day\":\"14-11-2019\",\"Hour\":\"08:31\"}",
        "Type": 8,
        "Time": "2019-11-14T08:31:00"
    }
],
"Success": true,
"ErrorMessage": null

}

这是我希望将其保存到的结构

struct Response: Decodable{

let ErrorMessage: String?
let Success: Bool
var data: [Data]

enum CodingKeys: String, CodingKey {
    case data = "Data"
    case Success, ErrorMessage
}
init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    self.data= try container.decode([Datas].self, forKey: .data)
    self.Success = try container.decode(Bool.self, forKey: .Success)
    self.ErrorMessage = try container.decode(String?.self, forKey: .ErrorMessage)
}

struct Data: Decodable{
    let `Type`: Int
    let  Id, PatientId : Int64
    let Form,Time: String
    enum CodingKeys: String, CodingKey {
        case Id, PatientId, Form,`Type`,Time
    }
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.PatientId = try container.decode(Int64.self, forKey: .PatientId)
        self.Id = try container.decode(Int64.self, forKey: .Id)
        self.Form = try container.decode(String.self, forKey: .Form)
        self.Time = try container.decode(String.self, forKey: .Time)
        self.`Type` = try container.decode(Int.self, forKey: .`Type`)
     }
 }

}

然后您可以使用以下方法解码 JSON:

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let response = try decoder.decode(Response.self, from: data)
print(response.data)

我使用此方法时的输出如下:

[]

我查看了 Apple 关于解码嵌套结构的文档,但我仍然不明白如何正确执行不同级别的 JSON。

---我解决这个问题的另一种方法:

let task = URLSession.shared.dataTask(with: request as URLRequest)
    {(data,response,error) -> Void in
        if error != nil
        {
            print(error?.localizedDescription as Any)
            return
        }
        do
        {
            guard error == nil else {
                return
            }

            guard let data = data else {
                return
            }

            //create json object from data
            if let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? NSDictionary {
                    print(json)
                    if let success = json["Success"] as? Bool {
                        self.sucBool = success as! Bool
                        if let array: NSArray = json["Data"]! as? NSArray{
                            for obj in array {
                                if let dict = obj as? NSDictionary {
                                    // Now reference the data you need using:
                                    let form= dict.value(forKey: "Form")
                                }
                            }
                        }
                    }
            }
            completionHandler(self.sucBool,nil)
        }
        catch let error as NSError
        {
            print(error.localizedDescription)
            completionHandler(false,error)
        }
    }
    task.resume()

我使用此方法时的输出如下:

{
Data =     (
);
ErrorMessage = "<null>";
Success = 1;

}

我可以正确读取 Web 服务响应,但对于 Data.casting 是错误的。我觉得这行代码关于强制转换有问题:

 if let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? NSDictionary

---此外,两种方法都不会写入错误消息。

标签: swiftjsonparser

解决方案


  1. 正如@Yvonne Aburrow 提到的那样,在 JSONlint.com 上检查您的 JSON
  2. 重构你的结构。您可以更轻松地编写它们!例子:
struct SomeRoot: Decodable {
    let data: [Data]
    let success: Bool
    let errorMessage: String?
}

struct Data: Decodable {
    let id: Int
    let patientId: Int
    let form: String
    let type: Int
    let time: String
}
do {
    let myFetchedJSON = try JSONDecoder().decode(SomeRoot.self, from: jsonObject!)
    print(myFetchedJSON.data)
} catch {
    print(error.localizedDescription)
}

...一些提示:

  • 对于解码 json,Decodable协议就足够了。您使用的Codable协议用于编码和解码。
  • 你需要do/catch尝试JSONDecoder().deco[...]块。如果您在catch {}块中打印错误,您会发现出了什么问题

推荐阅读