Swift 4 Codable:将 JSON return 字符串转换为 Int/Date/Float
Swift 4 Codable: Converting JSON return String to Int/Date/Float
我正在研究一些项目并删除 JSON 解析框架,因为使用它似乎很简单 Swift 4. 我遇到过这个奇怪的人 JSON return 其中 Ints
和 Dates
被 return 编辑为 Strings
.
我查看了 GrokSwift's Parsing JSON with Swift 4, Apple's website,但我没有看到任何关于 re: changing types 的内容。
Apple's example code 展示了如何更改键名,但我很难弄清楚如何更改键类型。
这是它的样子:
{
"WaitTimes": [
{
"CheckpointIndex": "1",
"WaitTime": "1",
"Created_Datetime": "10/17/2017 6:57:29 PM"
},
{
"CheckpointIndex": "2",
"WaitTime": "6",
"Created_Datetime": "10/12/2017 12:28:47 PM"
},
{
"CheckpointIndex": "0",
"WaitTime": "8",
"Created_Datetime": "9/26/2017 5:04:42 AM"
}
]
}
我已经使用 CodingKey
将字典键重命名为符合 Swift 的条目,如下所示:
struct WaitTimeContainer: Codable {
let waitTimes: [WaitTime]
private enum CodingKeys: String, CodingKey {
case waitTimes = "WaitTimes"
}
struct WaitTime: Codable {
let checkpointIndex: String
let waitTime: String
let createdDateTime: String
private enum CodingKeys: String, CodingKey {
case checkpointIndex = "CheckpointIndex"
case waitTime = "WaitTime"
case createdDateTime = "Created_Datetime"
}
}
}
我仍然 String
应该是 Int
或 Date
。我将如何使用 Codable 协议将包含 Int/Date/Float
作为 String
的 JSON return 转换为 Int/Date/Float
?
这是 ,因为 Swift 团队在 JSONDecoder 中仅提供了 String to date 解码器。
您始终可以手动解码:
struct WaitTimeContainer: Decodable {
let waitTimes: [WaitTime]
private enum CodingKeys: String, CodingKey {
case waitTimes = "WaitTimes"
}
struct WaitTime:Decodable {
let checkpointIndex: Int
let waitTime: Float
let createdDateTime: Date
init(checkpointIndex: Int, waitTime: Float, createdDateTime:Date) {
self.checkpointIndex = checkpointIndex
self.waitTime = waitTime
self.createdDateTime = createdDateTime
}
static let formatter: DateFormatter = {
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "MM/dd/yyyy hh:mm:ss a"
return formatter
}()
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let checkpointIndexString = try container.decode(String.self, forKey: .checkpointIndex)
let checkpointIndex = Int(checkpointIndexString)!
let waitTimeString = try container.decode(String.self, forKey: .waitTime)
let waitTime = Float(waitTimeString)!
let createdDateTimeString = try container.decode(String.self, forKey: .createdDateTime)
let createdDateTime = WaitTime.formatter.date(from: createdDateTimeString)!
self.init(checkpointIndex:checkpointIndex, waitTime:waitTime, createdDateTime:createdDateTime)
}
private enum CodingKeys: String, CodingKey {
case checkpointIndex = "CheckpointIndex"
case waitTime = "WaitTime"
case createdDateTime = "Created_Datetime"
}
}
}
public extension KeyedDecodingContainer {
public func decode(_ type: Date.Type, forKey key: Key) throws -> Date {
let dateString = try self.decode(String.self, forKey: key)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM/dd/yyyy hh:mm:ss a"
guard let date = dateFormatter.date(from: dateString) else {
let context = DecodingError.Context(codingPath: codingPath,
debugDescription: "Could not parse json key to a Date")
throw DecodingError.dataCorrupted(context)
}
return date
}
}
用法:-
let date: Date = try container.decode(Date.self, forKey: . createdDateTime)
我正在研究一些项目并删除 JSON 解析框架,因为使用它似乎很简单 Swift 4. 我遇到过这个奇怪的人 JSON return 其中 Ints
和 Dates
被 return 编辑为 Strings
.
我查看了 GrokSwift's Parsing JSON with Swift 4, Apple's website,但我没有看到任何关于 re: changing types 的内容。
Apple's example code 展示了如何更改键名,但我很难弄清楚如何更改键类型。
这是它的样子:
{
"WaitTimes": [
{
"CheckpointIndex": "1",
"WaitTime": "1",
"Created_Datetime": "10/17/2017 6:57:29 PM"
},
{
"CheckpointIndex": "2",
"WaitTime": "6",
"Created_Datetime": "10/12/2017 12:28:47 PM"
},
{
"CheckpointIndex": "0",
"WaitTime": "8",
"Created_Datetime": "9/26/2017 5:04:42 AM"
}
]
}
我已经使用 CodingKey
将字典键重命名为符合 Swift 的条目,如下所示:
struct WaitTimeContainer: Codable {
let waitTimes: [WaitTime]
private enum CodingKeys: String, CodingKey {
case waitTimes = "WaitTimes"
}
struct WaitTime: Codable {
let checkpointIndex: String
let waitTime: String
let createdDateTime: String
private enum CodingKeys: String, CodingKey {
case checkpointIndex = "CheckpointIndex"
case waitTime = "WaitTime"
case createdDateTime = "Created_Datetime"
}
}
}
我仍然 String
应该是 Int
或 Date
。我将如何使用 Codable 协议将包含 Int/Date/Float
作为 String
的 JSON return 转换为 Int/Date/Float
?
这是
您始终可以手动解码:
struct WaitTimeContainer: Decodable {
let waitTimes: [WaitTime]
private enum CodingKeys: String, CodingKey {
case waitTimes = "WaitTimes"
}
struct WaitTime:Decodable {
let checkpointIndex: Int
let waitTime: Float
let createdDateTime: Date
init(checkpointIndex: Int, waitTime: Float, createdDateTime:Date) {
self.checkpointIndex = checkpointIndex
self.waitTime = waitTime
self.createdDateTime = createdDateTime
}
static let formatter: DateFormatter = {
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "MM/dd/yyyy hh:mm:ss a"
return formatter
}()
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let checkpointIndexString = try container.decode(String.self, forKey: .checkpointIndex)
let checkpointIndex = Int(checkpointIndexString)!
let waitTimeString = try container.decode(String.self, forKey: .waitTime)
let waitTime = Float(waitTimeString)!
let createdDateTimeString = try container.decode(String.self, forKey: .createdDateTime)
let createdDateTime = WaitTime.formatter.date(from: createdDateTimeString)!
self.init(checkpointIndex:checkpointIndex, waitTime:waitTime, createdDateTime:createdDateTime)
}
private enum CodingKeys: String, CodingKey {
case checkpointIndex = "CheckpointIndex"
case waitTime = "WaitTime"
case createdDateTime = "Created_Datetime"
}
}
}
public extension KeyedDecodingContainer {
public func decode(_ type: Date.Type, forKey key: Key) throws -> Date {
let dateString = try self.decode(String.self, forKey: key)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM/dd/yyyy hh:mm:ss a"
guard let date = dateFormatter.date(from: dateString) else {
let context = DecodingError.Context(codingPath: codingPath,
debugDescription: "Could not parse json key to a Date")
throw DecodingError.dataCorrupted(context)
}
return date
}
}
用法:-
let date: Date = try container.decode(Date.self, forKey: . createdDateTime)