Я просматриваю некоторые проекты и удаляю рамки JSON для синтаксического анализа, так как это кажется довольно простым для Swift 4. Я столкнулся с этим возвратом JSON с нечетным кодом, где Ints
и Dates
возвращаются как Strings
.
Я посмотрел на GrokSwift Parsing JSON с Swift 4, Apple сайт, но я не вижу ничего, что выпрыгивает из: изменение типов.
Пример кода Apple показывает, как изменять имена ключей, но мне сложно определить, как изменить тип ключа.
Вот как это выглядит:
{
"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
. Как мне перейти на преобразование возврата JSON, содержащего Int/Date/Float
как String
в Int/Date/Float
, используя протокол Codable?
Это пока не возможно, так как команда Swift предоставила только декодер String to date в JSONDecoder.
Вы всегда можете декодировать вручную:
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)