Je voudrais faire une logique d'initialisation après que la fonction Swift Coding/Encoding a fini de décoder un JSON.
struct MyStruct: Codable {
let id: Int
var name: String
init() {
name = "\(id) \(name)"
}
}
Mais j'obtiens l'erreur du compilateur:
Return from initializer without initializing all stored properties
Ce qui est clair pour moi car init () veut que j'initialise toutes les propriétés. Mais l'ajout d'un init () avec toutes les propriétés nécessaires ne le résout pas non plus car cet initialiseur n'est pas appelé (!) Lorsque Codable entre en action:
init(id: Int, name: String) {
// This initializer is not called if Decoded from JSON!
self.id = id
self.name = "\(id) \(name)"
}
Néanmoins - existe-t-il un moyen de faire une logique d'initialisation après la fin du décodage, mais sans faire tout le décodage manuellement pour chaque propriété? Donc sans implémenter à chaque fois init(from decoder: Decoder)
. Dans ce court exemple, je n'ai que deux propriétés simples, mais le code de production se compose de milliers d'entre elles.
Merci.
Soit vous obtenez tout gratuitement mais standardisé ou vous devez écrire un initialiseur personnalisé comme
struct MyStruct: Codable {
let id: Int
var name: String
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(Int.self, forKey: .id)
let decodedName = try container.decode(String.self, forKey: .name)
name = "\(id) \(decodedName)"
}
}
Vous pouvez implémenter init()
mais cela fonctionne indépendamment de la fonctionnalité de décodage et vous devez attribuer une valeur par défaut à toutes les propriétés non facultatives, c'est ce que l'erreur indique.
Utilisez une méthode d'usine qui utilise d'abord init(from:)
puis appelle votre code d'initialisation personnalisé
struct Foo: Decodable {
let name: String
let id: Int
var x: String!
private mutating func finalizeInit() {
self.x = "\(name) \(id)"
}
static func createFromJSON(_ data: Data) -> Foo? {
guard var f = try? JSONDecoder().decode(Foo.self, from: data) else {
return nil
}
f.finalizeInit()
return f
}
}
let sampleData = """
{ "name": "foo", "id": 42 }
""".data(using: .utf8)!
let f = Foo.createFromJSON(sampleData)