【问题标题】:How to handle a mix of standard and customized Swift 4 Decodable properties?如何处理标准和自定义 Swift 4 Decodable 属性的混合?
【发布时间】:2019-02-08 18:19:29
【问题描述】:

我一直在尝试使用自定义的 Decodable 属性来处理 Swift 4 中的 JSON,我对映射棘手的类型和格式转换的易用性印象深刻。

但是,在服务器向我公开的 JSON 数据结构中,只有少数属性需要这种处理。其余的是简单的整数和字符串。有什么方法可以将定制解码器与标准解码器混合使用吗?

这是一个简化的示例,展示了我想要摆脱的内容:

struct mystruct : Decodable {
    var myBool: Bool
    var myDecimal: Decimal
    var myDate: Date
    var myString: String
    var myInt: Int
}

extension mystruct {
    private struct JSONsource: Decodable {
        var my_Bool: Int
        var my_Decimal: String
        var my_Date: String

        // These seem redundant, how can I remove them?
        var myString: String
        var myInt: Int
    }

    private enum CodingKeys: String, CodingKey {
        case item
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let item = try container.decode(JSONsource.self, forKey: .item)
        myBool = item.my_Bool == 1 ? true : false
        myDecimal = Decimal(string: item.my_Decimal)!
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSSZZZZZ"
        dateFormatter.locale = Locale(identifier: "en_US_POSIX")
        myDate = dateFormatter.date(from: item.my_Date)!

        // Can I somehow get rid of this redundant-looking code?
        myString = item.myString
        myInt = item.myInt
    }
}


let myJSON = """
{
    "item": {
        "my_Decimal": "123.456",
        "my_Bool" : 1,
        "my_Date" : "2019-02-08T11:14:31.4547774-05:00",
        "myInt" : 148727,
        "myString" : "Hello there!"
    }
}
""".data(using: .utf8)

let x = try JSONDecoder().decode(mystruct.self, from: myJSON!)

print("My decimal: \(x.myDecimal)")
print("My bool: \(x.myBool)")
print("My date: \(x.myDate)")
print("My int: \(x.myInt)")
print("My string: \(x.myString)")

【问题讨论】:

    标签: swift4 codable


    【解决方案1】:

    JSONDecoder 有一个 dateDecodingStrategy。无需手动解码。为了简化解码您的编码密钥,您可以将解码器属性.keyDecodingStrategy 设置为. convertFromSnakeCase。您还有一些类型不匹配,您可以处理添加计算属性。顺便说一句,这可能有助于为您的 ISO8601 日期字符串创建带有小数秒的自定义格式化程序。 How to create a date time stamp and format as ISO 8601, RFC 3339, UTC time zone? 。最后但并非最不重要的一点是,使用 UpperCamelCase 命名结构是 Swift 惯例

    struct Root: Codable {
        let item: Item
    }
    

    struct Item : Codable {
        var myBool: Int
        var myDecimal: String
        var myDate: Date
        var myString: String
        var myInt: Int
    }
    

    extension Item {
        var bool: Bool {
            return myBool == 1
        }
        var decimal: Decimal? {
            return Decimal(string: myDecimal)
        }
    }
    

    extension Item: CustomStringConvertible {
        var description: String {
            return "Iten(bool: \(bool), decimal: \(decimal ?? 0), date: \(myDate), string: \(myString), int: \(myInt))"
        }
    }
    

    let decoder = JSONDecoder()
    decoder.keyDecodingStrategy = .convertFromSnakeCase
    
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSSZZZZZ"
    dateFormatter.locale = Locale(identifier: "en_US_POSIX")
    decoder.dateDecodingStrategy = .formatted(dateFormatter)
    

    do {
        let item = try decoder.decode(Root.self, from: myJSON).item
        print(item)  // Iten(bool: true, decimal: 123.456, date: 2019-02-08 16:14:31 +0000, string: Hello there!, int: 148727)
    }
    catch {
        print(error)
    }
    

    【讨论】:

    • 确定检查。我有大约 40 个属性需要检查,所以我会在完成它们后发布我的结果。谢谢。
    • 我花了一些时间,但我经历了所有的财产。 dateDecodingStrategy 工作。谢谢!
    猜你喜欢
    • 2019-03-19
    • 1970-01-01
    • 2013-06-18
    • 2018-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-07
    • 2016-04-27
    相关资源
    最近更新 更多