Je crois que dans le cas d'un héritage, vous devez mettre en œuvre Coding
vous-même. C'est-à-dire que vous devez spécifier CodingKeys
et mettre en œuvre init(from:)
y encode(to:)
dans la superclasse et la sous-classe. Selon la Vidéo de la WWDC (vers 49:28, image ci-dessous), vous devez appeler super avec l'encodeur/décodeur super.
required init(from decoder: Decoder) throws {
// Get our container for this subclass' coding keys
let container = try decoder.container(keyedBy: CodingKeys.self)
myVar = try container.decode(MyType.self, forKey: .myVar)
// otherVar = ...
// Get superDecoder for superclass and call super.init(from:) with it
let superDecoder = try container.superDecoder()
try super.init(from: superDecoder)
}
La vidéo ne semble pas montrer l'aspect encodage (mais c'est container.superEncoder()
pour le encode(to:)
) mais cela fonctionne de la même manière dans votre encode(to:)
mise en œuvre. Je peux confirmer que cela fonctionne dans ce cas simple (voir le code du terrain de jeu ci-dessous).
Je suis moi-même toujours aux prises avec un comportement étrange dans un modèle beaucoup plus complexe que je suis en train de convertir. NSCoding
qui comporte un grand nombre de types nouvellement imbriqués (notamment struct
y enum
) qui présente ce phénomène inattendu nil
comportement et "ne devrait pas être". Sachez simplement qu'il peut y avoir des cas limites impliquant des types imbriqués.
Edit : Les types imbriqués semblent fonctionner correctement dans mon environnement de test ; je soupçonne maintenant que quelque chose ne va pas avec les classes auto-référencées (pensez aux enfants des nœuds d'arbre) avec une collection d'elle-même qui contient également des instances des différentes sous-classes de cette classe. Un test d'une simple classe auto-référencée se décode bien (c'est-à-dire qu'il n'y a pas de sous-classes). Je concentre donc mes efforts sur la raison pour laquelle le cas des sous-classes échoue.
Mise à jour du 25 juin 17 : J'ai fini par déposer un bug auprès d'Apple à ce sujet. rdar://32911973 - Malheureusement, un cycle de codage/décodage d'un tableau de Superclass
qui contient Subclass: Superclass
aura pour résultat que tous les éléments du tableau seront décodés en tant que Superclass
(la "sous-classe init(from:)
n'est jamais appelé, ce qui entraîne une perte de données ou pire).
//: Fully-Implemented Inheritance
class FullSuper: Codable {
var id: UUID?
init() {}
private enum CodingKeys: String, CodingKey { case id }
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(UUID.self, forKey: .id)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
}
}
class FullSub: FullSuper {
var string: String?
private enum CodingKeys: String, CodingKey { case string }
override init() { super.init() }
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let superdecoder = try container.superDecoder()
try super.init(from: superdecoder)
string = try container.decode(String.self, forKey: .string)
}
override func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(string, forKey: .string)
let superencoder = container.superEncoder()
try super.encode(to: superencoder)
}
}
let fullSub = FullSub()
fullSub.id = UUID()
fullSub.string = "FullSub"
let fullEncoder = PropertyListEncoder()
let fullData = try fullEncoder.encode(fullSub)
let fullDecoder = PropertyListDecoder()
let fullSubDecoded: FullSub = try fullDecoder.decode(FullSub.self, from: fullData)
Les propriétés super- et subclass sont rétablies dans le fichier fullSubDecoded
.
1 votes
Intéressant. Avez-vous signalé un bug à Apple ?
1 votes
Ce n'est pas un bug, c'est littéralement une "fonctionnalité non documentée". :-) La seule référence à (la moitié de) la solution était dans la vidéo WWDC 2017 "What's New In Foundation", détaillée dans ma réponse ci-dessous.