Je suis en train de parcourir des projets et de supprimer des frameworks d'analyse JSON, comme cela semble assez simple à faire avec Swift 4. J'ai rencontré ce retour JSON bizarre où Ints
et Dates
sont renvoyés sous la forme Strings
.
J'ai jeté un œil à Parsing JSON de GrokSwift avec Swift 4 , Site Web d'Apple , mais je ne vois rien qui saute aux yeux en ce qui concerne le changement de type.
L'exemple de code d'Apple montre comment changer les noms de clé, mais j'ai du mal à comprendre comment changer le type de clé.
Voici à quoi ça ressemble:
{
"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"
}
]
}
J'ai utilisé CodingKey
pour renommer les clés de dictionnaire en une entrée conforme à Swift, comme suit:
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"
}
}
}
Cela me laisse toujours avec String
qui devrait être Int
ou Date
. Comment procéder pour convertir une déclaration JSON contenant un Int/Date/Float
en tant que String
en un Int/Date/Float
à l'aide du protocole Codable?
Ceci est pas encore possible car l’équipe Swift n’a fourni que le décodeur String to date dans JSONDecoder.
Vous pouvez toujours décoder manuellement si:
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
}
}
Utilisation: -
let date: Date = try container.decode(Date.self, forKey: . createdDateTime)