Swift JSONDecode декодирование массивов / словарь не удается - PullRequest
0 голосов
/ 19 апреля 2020

Это была структура, которую я использовал

struct earthquakeResults: Codable{
    let datetime: String
    let depth: String
    //let eqid: Any
    let lat: String
    let lng: String
    let magnitude: String
    //let src: Any
}

Это когда я пытался получить результат JSON, и я использовал геокодер для получения long / lat, который я затем использовал для получения север / юг / восток / запад для вызова API

let urlAsString = "http://api.geonames.org/earthquakesJSON?north=\(north)&south=\(south)&east=\(east)&west=\(west)&username=antoniogomez"

let url = URL(string: urlAsString)!
        let urlSession = URLSession.shared


        let jsonQuery = urlSession.dataTask(with: url, completionHandler: { data, response, error -> Void in
            if (error != nil) {
                print(error!.localizedDescription)
            }
            var err: NSError?

            let decoder = JSONDecoder()

            let jsonResult = try! decoder.decode([earthquakeResults].self, from: data!)

            if (err != nil) {
                print("JSON Error \(err!.localizedDescription)")
            }

            print(jsonResult)

            let dt = jsonResult[0].datetime
            let dp = jsonResult[0].depth
            let lt = jsonResult[0].lat
            let lg = jsonResult[0].lng
            let mag = jsonResult[0].magnitude

            let res = "Results : \(dt) \(dp) \(lt) \(lg) \(mag)"
            print(res)
})

        jsonQuery.resume()

Я получаю сообщение об ошибке:

Тема 3: Неустранимая ошибка: 'попробуй!' Выражение неожиданно вызвало ошибку: Swift.DecodingError.typeMismatch (Swift.Array, Swift.DecodingError.Context (codingPath: [], debugDescription: «Ожидается декодировать массив, но вместо этого найден словарь.», базовыйError: nil))

вот как JSON выглядело:

{
    earthquakes =     (
                {
            datetime = "2012-10-09 10:32:04";
            depth = "10.2";
            eqid = c000d4li;
            lat = "-61.0333";
            lng = "153.9596";
            magnitude = "6.4";
            src = us;
        },
                {
            datetime = "2013-01-15 15:09:36";
            depth = 10;
            eqid = b000epcu;
            lat = "-62.5663";
            lng = "-161.3457";
            magnitude = "6.1";
            src = us;
        },
                {
            datetime = "2019-07-23 10:33:10";
            depth = 10;
            eqid = us70004r4f;
            lat = "-61.2936";
            lng = "154.063";
            magnitude = 6;
            src = us;
        },
                {
            datetime = "2016-01-31 17:43:40";
            depth = 10;
            eqid = us20004w6c;
            lat = "-63.2868";
            lng = "169.1522";
            magnitude = 6;
            src = us;
        },
                {
            datetime = "2016-02-23 18:10:40";
            depth = "7.71";
            eqid = us10004s4c;
            lat = "-63.1275";
            lng = "144.7936";
            magnitude = "5.9";
            src = us;
        },
                {
            datetime = "2017-06-03 19:32:50";
            depth = 10;
            eqid = us20009kit;
            lat = "-62.5792";
            lng = "155.834";
            magnitude = "5.9";
            src = us;
        },
                {
            datetime = "2010-12-24 04:48:54";
            depth = "10.7";
            eqid = c0000ueu;
            lat = "-63.5903";
            lng = "-167.4271";
            magnitude = "5.9";
            src = us;
        },
                {
            datetime = "2007-11-04 19:35:36";
            depth = "7.5";
            eqid = 2007jhax;
            lat = "-67.1317";
            lng = "111.5551";
            magnitude = "5.8";
            src = us;
        },
                {
            datetime = "2007-08-02 22:41:16";
            depth = "11.7";
            eqid = 2007fpab;
            lat = "-62.8736";
            lng = "145.4634";
            magnitude = "5.7";
            src = us;
        },
                {
            datetime = "2006-03-23 12:57:41";
            depth = 10;
            eqid = kqbp;
            lat = "-62.5198";
            lng = "164.8179";
            magnitude = "5.7";
            src = us;
        }
    );
}

И это то, что я делал изначально, но я не мог понять, как получить дату, время и величину ( или любой другой детали), поэтому я решил, что вместо этого попробую использовать декодер:

var jsonResult = (try! JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers)) as! NSDictionary
if (err != nil) {
    print("JSON Error \(err!.localizedDescription)")
}

Ответы [ 2 ]

1 голос
/ 19 апреля 2020

Приведенный выше ответ Кямрана хорош.

Однако вам нужно изменить «Настройки безопасности транспорта приложений» в файле plist, чтобы позволить ссылке получить данные ... например, так:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>api.geonames.org</key>
        <dict>
            <key>NSIncludesSubdomains</key>
            <true/>
            <key>NSThirdPartyExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>
    </dict>
</dict>

добавьте приведенный выше фрагмент в файл plist под первой парой строк:

</plist>
</dict>

И, наконец, вам нужно изменить тип данных для вашей структуры. Вы пытаетесь получить String, когда JSON возвращает Double. Поэтому измените структуру с ответа выше на это:

    struct Earthquake: Codable {
    let datetime: String
    let depth: Double
    let lat: Double
    let lng: Double
    let magnitude: Double

    enum CodingKeys: String, CodingKey {
        case datetime = "datetime"
        case depth = "depth"
        case lat = "lat"
        case lng = "lng"
        case magnitude = "magnitude"
    }
}
1 голос
/ 19 апреля 2020

Из ответа вы получаете json (не массив json), который содержит ожидаемый список json объектов. Таким образом, ваш ответ будет декодирован как объект, имеющий этот список. Создайте типы данных, как показано ниже.

struct Result: Codable {
    let earthquakes: [Earthquake]

    enum CodingKeys: String, CodingKey {
        case earthquakes = "earthquakes"
    }
}

// MARK: - Earthquake
struct Earthquake: Codable {
    let datetime: String
    let depth: String
    let lat: String
    let lng: String
    let magnitude: String

    enum CodingKeys: String, CodingKey {
        case datetime = "datetime"
        case depth = "depth"
        case lat = "lat"
        case lng = "lng"
        case magnitude = "magnitude"
    }
}

И проанализируйте результат как,

let urlAsString = "http://api.geonames.org/earthquakesJSON?north=\(north)&south=\(south)&east=\(east)&west=\(west)&username=antoniogomez"

let url = URL(string: urlAsString)!
        let urlSession = URLSession.shared


        let jsonQuery = urlSession.dataTask(with: url, completionHandler: { data, response, error -> Void in
            if (error != nil) {
                print(error!.localizedDescription)
            }
            var err: NSError?

            let decoder = JSONDecoder()

            let jsonResult = try! decoder.decode(Result.self, from: data!)

            if (err != nil) {
                print("JSON Error \(err!.localizedDescription)")
            }

            print(jsonResult.earthquakes)

            let dt = jsonResult.earthquakes[0].datetime
            let dp = jsonResult.earthquakes[0].depth
            let lt = jsonResult.earthquakes[0].lat
            let lg = jsonResult.earthquakes[0].lng
            let mag = jsonResult.earthquakes[0].magnitude

            let res = "Results : \(dt) \(dp) \(lt) \(lg) \(mag)"
            print(res)
})

        jsonQuery.resume()
...