一尘不染

JSON请求并不总是返回相同的响应类型(对象和数组)

swift

TL; DR:一个JSON请求有时返回一个对象,有时返回一个键的对象数组,但我不知道如何使用Swift 4正确解析该对象。

前言:我正在使用NextBus
API
制作公共汽车服务应用程序,以提供教堂山地区公共汽车的公共汽车时刻表更新和预测。但是,在获取公交车站的预测信息时遇到问题(
NextBus API PDF的pp 13-15页上的预测请求信息 )。

问题:

停止预测的请求返回两个键:“预测”和“版权”。尽管“版权”键始终返回用于预测请求的字符串,但“预测”键有时会返回对象,有时会根据路线上是否有两条公交车返回数组。

这是Postman可视化的问题:

预测返回一个数组:

{
"predictions": [
    {
        "agencyTitle": "Chapel Hill Transit",
        "routeTag": "N",
        "routeTitle": "N",
        "stopTitle": "Estes Park Apts - Departure",
        "stopTag": "estepark",
        "dirTitleBecauseNoPredictions": "To Family Practice Building"
    },
    {
        "agencyTitle": "Chapel Hill Transit",
        "routeTag": "N",
        "routeTitle": "N",
        "stopTitle": "Estes Park Apts - Arrival",
        "stopTag": "estepark_a",
        "dirTitleBecauseNoPredictions": "To Family Practice Building"
    }
],
"copyright": "All data copyright Chapel Hill Transit 2018." 
}

预测返回一个对象:

{
"predictions": {
    "agencyTitle": "Chapel Hill Transit",
    "routeTag": "A",
    "routeTitle": "A",
    "stopTitle": "Martin Luther King Jr Blvd  at Timber Hollow",
    "stopTag": "airptimb_s",
    "dirTitleBecauseNoPredictions": "To Northside"
},
"copyright": "All data copyright Chapel Hill Transit 2018."
}

我正在使用Swift 4在Xcode 9.4.1中创建此应用程序。这是当前处理请求的代码:

func fetchStopPrediction(stopId: String, routeTag: String, completion: @escaping (Predictions) -> Void) {
    let routeInfo = "\(stopId)&routeTag=\(routeTag)"
    let urlString = baseUrl + routeInfo
    print(urlString)

    Alamofire.request(urlString, method: .get).responseJSON { (response) in
        if let jsonResponse = response.result.value {
            print("JSON: \(jsonResponse)")
        }

        if let data = response.data {
            do {
                let predictions = try self.decoder.decode(Predictions.self, from: data)
                completion(predictions)
            } catch let error {
                print("Error", error)
            }
        }
    }
}

struct Predictions: Codable {
    let predictions: [Prediction?]
    let copyright: String?
}

阅读 200

收藏
2020-07-07

共1个答案

一尘不染

您必须编写一个自定义初始化程序。首先解码字典,如果字典解码失败

struct Predictions : Decodable {
    let predictions: [Prediction]
    let copyright: String

    private enum CodingKeys: String, CodingKey { case predictions, copyright }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        copyright = try container.decode(String.self, forKey: .copyright)
        do {
            let prediction = try container.decode(Prediction.self, forKey: .predictions)
            predictions = [prediction]
        } catch DecodingError.typeMismatch {
            predictions = try container.decode([Prediction].self, forKey: .predictions)
        }
    }
}
2020-07-07