Swift 4·数据转换

时间:2018-06-18 11:50:19

标签: ios json swift

我在iOS中创建了一个模拟时钟显示器,它也显示了太阳正午和中午之间的区别,所以我需要知道太阳中午的时间才能计算出这个差异。

此api调用:http://api.usno.navy.mil/rstt/oneday?date=today&coords=51.1,-1.0&tz=1产生以下结果(丢弃一些不相关的字段):

{
    "year":2018,
    "month":6,
    "day":18,
    "lon":-1.000000,
    "lat":51.100000,
    "tz":1,
    "sundata":[
        {"phen":"BC", "time":"04:02"},
        {"phen":"R", "time":"04:49"},
        {"phen":"U", "time":"13:05"},  <-- ( Upper Transit/Solar Noon )
        {"phen":"S", "time":"21:22"},
        {"phen":"EC", "time":"22:09"}]
} 

此时我只对太阳中午的当地时间感兴趣(如上例所示“13:05”)并将其转换为中午时间以后的分钟数 - 这对于我的显示目的而言足够准确。

为此,我将数据提取到此Swift结构中:

struct SolarData: Decodable {
    let year: Int
    let month: Int
    let day: Int
    let lon: Double
    let lat: Double
    let tz: Double
    let sundata:  Array<[String: String]>

    /// The number of minutes past clock noon at which solar noon occurs.
    public var solarNoonOffset: Int {
        let noon = sundata
                      .filter { $0["phen"] == "U" }
                      .flatMap { $0 }
                      .filter { $0.0 == "time" }[0]
                      .value
        let solarNoonHour = Int(noon.prefix(2))
        let solarNoonMins = Int(noon.suffix(2))
        let offset        = (solarNoonHour! - 12) * 60 + solarNoonMins!
        return offset
    }
}

这有效,但感觉既笨拙又冗长(即使删除了所有错误检查以简化示例),所以我有两个相关的问题:

  1. 在结构中,let sundata: Array<[String: String]>是否与数据有效匹配或过于通用?

  2. 可以在多大程度上简化偏移的计算?

1 个答案:

答案 0 :(得分:1)

这些方面应该有所作为。基本上,您希望为phen项目创建课程。您甚至可以使用枚举来提高可读性。

我确信您还可以采取其他措施来提高可读性,例如定义自己的CodingKeys枚举,为您的网站提供更好的名称,但这取决于您。这应该可以帮到你。

struct SolarData: Decodable {

    struct Phenomenon: Decodable {

        enum Kind: String, Decodable {
            case
            beginCivilTwilight = "BC",
            rise = "R",
            upperTransit = "U",
            set = "S",
            endCivilTwilight = "EC",
            lowerTransit = "L"
        }

        var phen: Kind
        var time: String
    }

    let year: Int
    let month: Int
    let day: Int
    let lon: Double
    let lat: Double
    let tz: Double
    let sundata:  [Phenomenon]

    /// The number of minutes past clock noon at which solar noon occurs.
    public var solarNoonOffset: Int {
        let noon = sundata
            .first { $0.phen == .upperTransit }
            .map { $0.time }
        let solarNoonHour = Int(noon!.prefix(2))
        let solarNoonMins = Int(noon!.suffix(2))
        let offset        = (solarNoonHour! - 12) * 60 + solarNoonMins!
        return offset
    }
}

let testJson = """
{
    "year":2018,
    "month":6,
    "day":18,
    "lon":-1.000000,
    "lat":51.100000,
    "tz":1,
    "sundata":[
        {"phen":"BC", "time":"04:02"},
        {"phen":"R", "time":"04:49"},
        {"phen":"U", "time":"13:05"},
        {"phen":"S", "time":"21:22"},
        {"phen":"EC", "time":"22:09"}]
}
"""

let solarData = try JSONDecoder().decode(SolarData.self, from: testJson.data(using: .utf8)!)

print("Solar Noon Offset: \(solarData.solarNoonOffset)")