Как гарантировать действительный JSON в Swift 4? - PullRequest
0 голосов
/ 29 апреля 2018

Я пытаюсь работать с данными JSON, возвращенными из службы. JSON, согласно валидаторам JSON, действителен и очень прост:

[{"ID":"SDS-T589863","TotalRisk":0.2458,"TotalScore":641.032}] 

Однако, пытаясь разобрать его в моем коде Swift 4, он загадочно (по крайней мере для меня) недействителен. Вот моя попытка разобрать его:

 // make the request
    let task = session.dataTask(with: urlRequest) {
        (data, response, error) in
        // check for any errors
        guard error == nil else {
            print(error!)
            return
        }
        // make sure we got data
        guard let responseData = data else {
            print("Error: did not receive data")
            return
        }

        // this is fine:
        guard let ddd = String(bytes: responseData, encoding: String.Encoding.utf8) else {
            print("can't")
            return
        }

        print(ddd) // prints [{"ID":"SDS-T589863","TotalRisk":0.2458,"TotalScore":641.032}] happily

        do {
            // cannot serialize
            guard let risk = try JSONSerialization.jsonObject(with: responseData, options: [JSONSerialization.ReadingOptions.allowFragments])
                as? [String: Any]
            else {
                    print("error trying to convert data to JSON")
                    return
            }
            print(risk)
        } catch  {
            print("error trying to convert data to JSON")
            return
            }
        }
    task.resume()

}

Предполагая, что у меня нет контроля над объектом JSON или форматом, в котором он мне возвращается, есть ли способ узнать, что не так с JSON, и, возможно, отформатировать ответ, чтобы его можно было правильно сериализовать?

Ответы [ 2 ]

0 голосов
/ 29 апреля 2018

Тип ответа - массив объектов json, поэтому вы должны привести его к [[String: Any]]. Поскольку вы используете Swift 4, вы можете использовать тип Decodable, который отображает модель в ответ.

     let task = URLSession().dataTask(with: urlRequest) { (data, response, error) in
        // check for any errors
        guard error == nil else {
            print(error!)
            return
        }
        // make sure we got data
        guard let responseData = data else {
            print("Error: did not receive data")
            return
        }

        do {
            let decoder = JSONDecoder()
            let riskArray = try decoder.decode([Risk].self, from: responseData)
            print(riskArray)
        } catch {
            print("error trying to convert data to Model")
            print(error.localizedDescription)
        }
    }
    task.resume()

Вы можете определить структуру вашей модели как

struct Risk: Decodable {
    let id: String
    let totalRisk: Double
    let totalScore: Double

    enum CodingKeys: String, CodingKey {
        case id = "ID"
        case totalRisk = "TotalRisk"
        case totalScore = "TotalScore"
    }
}

Подробнее о декодируемом протоколе можно прочитать здесь

0 голосов
/ 29 апреля 2018

Вы должны привести ваши данные к типу [[String: Any]], потому что у вас есть массив в ответ.

Вы пытаетесь привести к [String: Any], но у вас есть массив [String: Any], потому что ваш ответ заключен в [] скобки.

Пример:

let risk = try JSONSerialization.jsonObject(with: responseData, options: [JSONSerialization.ReadingOptions.allowFragments]) as? [[String: Any]]

Или, если вы хотите получить только один [String: Any] объект из ответа, вы можете написать:

let risk = (try JSONSerialization.jsonObject(with: responseData, options: [JSONSerialization.ReadingOptions.allowFragments]) as? [[String: Any]])?.first

Или, если ваш объект может быть массивом или не массивом (но это звучит немного странно), вы можете попытаться привести к нескольким возможным типам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...