解析Json数组而无需按键swift 4

时间:2019-03-14 14:59:26

标签: ios arrays json swift parsing

我坚持解析JSON。结构真的很难。我正在尝试一种可解码的方法。

import UIKit

struct WeatherItem: Decodable {
    let title: String?
    let value: String?
    let condition: String?
}

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        print("hello")

        let jsonUrlString = "http://virtualflight.ddns.net/api/weather.php?icao=ehrd"
        guard let url = URL(string: jsonUrlString) else { return }

        URLSession.shared.dataTask(with: url) { (data, response, err) in
            guard let data = data else { return }

            var arr = [WeatherItem]()
            do {
                let res = try JSONDecoder().decode([String:[[String]]].self, from: data)
                let content = res["title"]!
                content.forEach {
                    if $0.count >= 3 {
                        arr.append(WeatherItem(title:$0[0],value:$0[1],condition:$0[2]))
                    }
                }
                print(arr)
            } catch {
                print(error)
            }
        }
    }
}

以下是json:

{
    "temperature": {
        "value_c": 11,
        "value_f": 285,
        "condition": "Good",
        "value_app": "11 \u00b0C (285 \u00b0F)"
    },
    "visibility": {
        "value_km": 10,
        "value_m": 6.2,
        "condition": "Good",
        "value_app": "10 KM (6.2 Mi)"
    },
    "pressure": {
        "value_hg": 29.4,
        "value_hpa": 996,
        "condition": "Good",
        "value_app": "29.4 inHg (996 hPa)"
    },
    "wind": {
        "value_kts": 20,
        "value_kmh": 37,
        "value_heading": 280,
        "condition": "Bad",
        "value_app": "280\u00b0 at 20 KTS (37 Km\/H)"
    },
    "station": "EHRD",
    "metar": "EHRD 141355Z AUTO 28020KT 250V320 9999 SCT038 BKN043 BKN048 11\/07 Q0996 NOSIG",
    "remarks": "NOSIG",
    "weather_page_ios_simple": [
        [
            "Temperature",
            "11 \u00b0C (285 \u00b0F)",
            "Good"
        ],
        [
            "Visibility",
            "10 KM (6.2 Mi)",
            "Good"
        ],
        [
            "Pressure",
            "29.4 inHg (996 hPa)",
            "Good"
        ],
        [
            "Wind",
            "280\u00b0 at 20 KTS (37 Km\/H)",
            "Bad"
        ],
        [
            "Metar",
            "EHRD 141355Z AUTO 28020KT 250V320 9999 SCT038 BKN043 BKN048 11\/07 Q0996 NOSIG",
            "Unknown"
        ],
        [
            "Remarks",
            "NOSIG",
            "Unknown"
        ],
        [
            "Station",
            "EHRD",
            "Unknown"
        ],
        [
            "UICell",
            "iOS 12",
            "siri_weather_cell"
        ]
    ]
}

任何想法如何做到这一点?我只需要最后一个数组weather_page_ios_simple。

2 个答案:

答案 0 :(得分:1)

看看https://app.quicktype.io,它将为您提供JSON的数据结构。

import Foundation

struct Welcome: Codable {
    let temperature: Temperature
    let visibility: Visibility
    let pressure: Pressure
    let wind: Wind
    let station, metar, remarks: String
    let weatherPageIosSimple: [[String]]

    enum CodingKeys: String, CodingKey {
        case temperature, visibility, pressure, wind, station, metar, remarks
        case weatherPageIosSimple = "weather_page_ios_simple"
    }
}

struct Pressure: Codable {
    let valueHg: Double
    let valueHpa: Int
    let condition, valueApp: String

    enum CodingKeys: String, CodingKey {
        case valueHg = "value_hg"
        case valueHpa = "value_hpa"
        case condition
        case valueApp = "value_app"
    }
}

struct Temperature: Codable {
    let valueC, valueF: Int
    let condition, valueApp: String

    enum CodingKeys: String, CodingKey {
        case valueC = "value_c"
        case valueF = "value_f"
        case condition
        case valueApp = "value_app"
    }
}

struct Visibility: Codable {
    let valueKM: Int
    let valueM: Double
    let condition, valueApp: String

    enum CodingKeys: String, CodingKey {
        case valueKM = "value_km"
        case valueM = "value_m"
        case condition
        case valueApp = "value_app"
    }
}

struct Wind: Codable {
    let valueKts, valueKmh, valueHeading: Int
    let condition, valueApp: String

    enum CodingKeys: String, CodingKey {
        case valueKts = "value_kts"
        case valueKmh = "value_kmh"
        case valueHeading = "value_heading"
        case condition
        case valueApp = "value_app"
    }
}

答案 1 :(得分:0)

如果仅需要底部数据数组,则无需将所有内容都放入解码后的结构中。只需解码所需的响应部分,然后从那里提取数据即可。此外,该数据数组实际上不是在没有键的情况下解析JSON。它只是一个字符串数组,您必须依靠这样的事实,即索引0始终是标题,索引1始终是值,索引2始终是条件。只是做一些验证,以确保它符合您的需求。像这样(未测试)

struct WeatherItem {

    let title: String?
    let value: String?
    let condition: String?

    init(title: String?, value: String?, condition: String?) {
        self.title = title
        self.value = value
        self.condition = condition
    }
}

struct WeatherResponse: Decodable {

    var weatherItems: [WeatherItem]

    private enum CodingKeys: String, CodingKey {
        case weatherItems = "weather_page_ios_simple"
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let weatherItemArrays = try container.decode([[String]].self, forKey: .weatherItems)

        weatherItems = []

        for weatherItemArray in weatherItemArrays {

            var title: String?

            if weatherItemArray.count > 0 {
                title = weatherItemArray[0]
            }

            var value: String?

            if weatherItemArray.count > 1 {
                value = weatherItemArray[1]
            }

            var condition: String?

            if weatherItemArray.count > 2 {
                condition = weatherItemArray[2]
            }

            weatherItems.append(WeatherItem(title: title, value: value, condition: condition))
        }
    }
}

然后,当您获得api响应时,请使用类似的内容

do {
    let weatherResponse = try JSONDecoder().decode(WeatherResponse.self, from: <YOUR API RESPONSE DATA>)
    let weatherItems = weatherResponse.weatherItems

    <DO WHATEVER YOU WANT WITH THE WEATHER ITEMS>

} catch let error {
    print(error)
}