swift4 - 如何处理标准和自定义 Swift 4 Decodable 属性的混合?
问题描述
我一直在尝试使用自定义的 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)")
解决方案
JSONDecoder 有一个 dateDecodingStrategy。无需手动解码。为了简化解码您的编码密钥,您可以将 decoders 属性设置.keyDecodingStrategy
为. convertFromSnakeCase
. 您还有一些类型不匹配,您可以处理添加计算属性。顺便说一句,这可能有助于为您的 ISO8601 日期字符串创建带有小数秒的自定义格式化程序。如何创建日期时间戳和格式为 ISO 8601、RFC 3339、UTC 时区?. 最后但并非最不重要的一点是,使用 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)
}
推荐阅读
- visio - visio 引用同一文档中的其他页面
- java - 传输文件时 JSch SFTP 代码挂起
- bash - Can a large amount of arguments deteriorate performance of a ksh or bash script?
- javascript - Find Video Duration From Content-Length in NodeJS
- java - 在java中的有限时间内在输出中写一些东西
- ruby - Reassemble jumbled method
- winapi - How to detect if Windows 10 is in tablet mode
- r - centos集群上的doparallel和foreach问题
- javascript - javascript onclick 功能不起作用
- python - 我如何在python中抓取网络特殊词