如何在Swift 4中解构此JSON

时间:2019-02-15 19:59:14

标签: json swift

在这里,我已经看过许多类似的问题,但是我无法理解我所缺少的东西。

我的JSON看起来像这样:

   {
    "Stations": [{
 {
        "Code": "A02",
        "Name": "Farragut North",
        "StationTogether1": "",
        "StationTogether2": "",
        "LineCode1": "RD",
        "LineCode2": null,
        "LineCode3": null,
        "LineCode4": null,
        "Lat": 38.903192,
        "Lon": -77.039766,
        "Address": {
            "Street": "1001 Connecticut Avenue NW",
            "City": "Washington",
            "State": "DC",
            "Zip": "20036"
        }
    }, {
        "Code": "A03",
        "Name": "Dupont Circle",
        "StationTogether1": "",
        "StationTogether2": "",
        "LineCode1": "RD",
        "LineCode2": null,
        "LineCode3": null,
        "LineCode4": null,
        "Lat": 38.909499,
        "Lon": -77.04362,
        "Address": {
            "Street": "1525 20th St. NW",
            "City": "Washington",
            "State": "DC",
            "Zip": "20036"
        }

我已经设置了Struct:

struct AllStations : Codable {

let stations: [String]?
let code: String?
let name: String?

let lat: Double?
let lon: Double?
let lineCode1: String?
let lineCode2: String?
let lineCode3: String?
let lineCode4: String?
let together1: String?
let together2: String?
let address: [String]?
let street: String?
let city: String?
let state: String?
let zip: String?

private enum CodingKeys: String, CodingKey {
    case stations = "Stations"
    case code = "Code"
    case name = "Name"

    case lat = "Lat"
    case lon = "Lon"
    case lineCode1 = "LineCode1"
    case lineCode2 = "LineCode2"
    case lineCode3 = "LineCode3"
    case lineCode4 = "LineCode4"
    case together1 = "StationTogether1"
    case together2 = "StationTogether2"
    case address = "Address"
    case street = "Street"
    case city = "City"
    case state = "State"
    case zip = "Zip"

}

init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)

    let response = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .stations)

    stations = try response.decode([String].self, forKey: .stations)

    code = try response.decode(String.self, forKey: .code)
    name = try response.decode(String.self, forKey: .name)

    lat = try response.decode(Double.self, forKey: .lat)
    lon = try response.decode(Double.self, forKey: .lon)
    lineCode1 = try response.decode(String.self, forKey: .lineCode1)
    lineCode2 = try response.decode(String.self, forKey: .lineCode2)
    lineCode3 = try response.decode(String.self, forKey: .lineCode3)
    lineCode4 = try response.decode(String.self, forKey: .lineCode4)
    together1 = try response.decode(String.self, forKey: .together1)
    together2 = try response.decode(String.self, forKey: .together2)
    address = try response.decode([String].self, forKey: .address)

    let anAddress = try response.nestedContainer(keyedBy: CodingKeys.self, forKey: .address)
    street = try anAddress.decode(String.self, forKey: .street)
    city = try anAddress.decode(String.self, forKey: .city)
    state = try anAddress.decode(String.self, forKey: .state)
    zip = try anAddress.decode(String.self, forKey: .zip)

}

}

我正在从URL检索数据并将其传递给我的解码器:

func processResponse(using data: Data?) {

        if let jsonData = data
        {
            let decoder = JSONDecoder()

            do {

                let allStations = try decoder.decode(AllStations.self, from: jsonData)

                print(#function, "A Station: ", allStations as Any)
            } catch {
                print(error.localizedDescription)
            }
        } else {
            // Respond to error
        }
    }

但是我遇到了格式化问题:“由于格式不正确,无法读取数据。”

我看不到我想念的东西。帮助将不胜感激。

2 个答案:

答案 0 :(得分:1)

很明显"Stations"的值实际上不是字符串数组。

您需要单独的嵌套对象:

struct Station: Decodable {
    let code: String?
    let name: String?

    let lat: Double?
    let lon: Double?
    let lineCode1: String?
    let lineCode2: String?
    let lineCode3: String?
    let lineCode4: String?
    let together1: String?
    let together2: String?
    let address: Address?

    private enum CodingKeys: String, CodingKey {
        case code = "Code"
        case name = "Name"

        case lat = "Lat"
        case lon = "Lon"
        case lineCode1 = "LineCode1"
        case lineCode2 = "LineCode2"
        case lineCode3 = "LineCode3"
        case lineCode4 = "LineCode4"
        case together1 = "StationTogether1"
        case together2 = "StationTogether2"
        case address = "Address"
    }
}

struct AllStations: Decodable {
    let stations: [Station]

    private enum CodingKeys: String, CodingKey {
        case stations = "Stations"
    }
}

Address本身必须是另一个嵌套对象:

struct Address: Decodable {
    let street: String?
    let city: String?
    let state: String?
    let zip: String?

    private enum CodingKeys: String, CodingKey {
        case street = "Street"
        case city = "City"
        case state = "State"
        case zip = "Zip"
    }
} 

答案 1 :(得分:1)

您可以执行此步骤以摆脱主根无用的结构

do {
  let tr = try JSONSerialization.jsonObject(with:data) as! [String:Any] 
  let staData = try JSONSerialization.data(withJSONObject:tr["Stations"]!, options:[]) 
  let allStations = try JSONDecoder().decode([Station].self, from:staData) 
} 
catch {
   print(error)
}