J'essaie de sérialiser une structure vers un String en utilisant Encodable+JSONEncoder de Swift 4. L'objet peut contenir des valeurs hétérogènes comme String, Array, Date, Int etc.
L'approche utilisée fonctionne bien, à l'exception de la date. La méthode de JSONEncoder dateEncodingStrategy
n'a pas d'effet.
Voici un extrait qui reproduit le comportement dans Playground :
struct EncodableValue:Encodable {
var value: Encodable
init(_ value: Encodable) {
self.value = value
}
func encode(to encoder: Encoder) throws {
try value.encode(to: encoder)
}
}
struct Bar: Encodable, CustomStringConvertible {
let key: String?
let value: EncodableValue?
var description: String {
let encoder = JSONEncoder()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "E, d MMM yyyy"
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
encoder.dateEncodingStrategy = .formatted(dateFormatter)
let jsonData = try? encoder.encode(self)
return String(data: jsonData!, encoding: .utf8)!
}
}
let bar1 = Bar(key: "bar1", value: EncodableValue("12345"))
let bar2 = Bar(key: "bar2", value: EncodableValue(12345))
let bar3 = Bar(key: "bar3", value: EncodableValue(Date()))
print(String(describing: bar1))
print(String(describing: bar2))
print(String(describing: bar3))
Sortie :
"{"key":"bar1","value":"12345"}\n"
"{"key":"bar2","value":12345}\n"
"{"key":"bar3","value":539682026.06086397}\n"
Pour l'objet bar3 : Je m'attends à quelque chose comme "{"key":"bar3","value":"Thurs, 3 Jan 1991"}\n"
mais il renvoie la date dans le format par défaut de la stratégie .deferToDate.
##EDIT 1###
J'ai donc exécuté le même code dans XCode 9 et il donne le résultat attendu, c'est-à-dire qu'il formate correctement la date en chaîne. Je pense que la 9.2 a une mise à jour mineure vers Swift 4 qui casse cette fonctionnalité. Je ne suis pas sûr de ce qu'il faut faire ensuite.
##EDIT 2##
Comme solution temporaire, j'ai utilisé l'extrait suivant avant de passer à l'approche de @Hamish qui utilise une fermeture.
struct EncodableValue:Encodable {
var value: Encodable
init(_ value: Encodable) {
self.value = value
}
func encode(to encoder: Encoder) throws {
if let date = value as? Date {
var container = encoder.singleValueContainer()
try container.encode(date)
}
else {
try value.encode(to: encoder)
}
}
}