当我解码子类(RegularCard(的数组时,我会得到超类(Card(的一个数组。编码很好,我测试了它,编码工作得很好。但是,当我解码时,不会调用解码子类的函数(RegularCard(。我的代码在下面。我在另一篇帖子中发现了以下错误:
2017年6月25日更新:我最终向苹果公司提交了一个关于这方面的错误。rdar://32911973-不幸的是,包含子类的超类数组的编码/解码循环:超类元素将导致数组中的所有元素被解码为超类(从未调用子类的init(from:(,导致数据丢失或更糟(。
这是在这篇文章中。
class Card : Codable {
var id: Int
var front: String
var score: Int
var cardType : CardType
init(id: Int, front : String, score: Int, cardType : CardType) {
self.id = id
self.front = front
self.score = score
self.cardType = cardType
}
enum CodingKeys : String, CodingKey {
case id
case front
case score
case cardType
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
print("encoding super")
try container.encode(id, forKey: .id)
try container.encode(front, forKey: .front)
try container.encode(score, forKey: .score)
try container.encode(cardType.rawValue, forKey: .cardType)
}
required init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
print("decoding super")
self.id = try values.decode(Int.self, forKey: .id)
self.front = try values.decode(String.self, forKey: .front)
self.score = try values.decode(Int.self, forKey: .score)
self.cardType = CardType(rawValue: try values.decode(String.self, forKey: .cardType))!
}
}
enum CardType : String {
case regular = "regular"
case multipleChoice = "multipleChoice"
case numbered = "numbered"
case bulleted = "bulleted"
case acronym = "acronym"
case image = "image"
}
class RegularCard : Card {
var back: String
init(id: Int, front : String, score: Int, back : String) {
self.back = back
super.init(id: id, front: front, score: score, cardType: .regular)
}
enum CodingKeys : String, CodingKey {
case back
case id
case front
case score
case cardType
}
override func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
print("encoding Regular")
try super.encode(to: encoder)
try container.encode(back, forKey: .back)
}
required init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
print("decoding regular")
back = try values.decode(String.self, forKey: .back)
try super.init(from: decoder)
}
}
''
对我来说很好:
let reg = RegularCard(id: 1, front: "yo", score: 20, back: "frf")
let arr = [reg]
let data = try! JSONEncoder().encode(arr)
let arr2 = try! JSONDecoder().decode([RegularCard].self, from: data)
print(type(of:arr2)) // Array<RegularCard>
let what = arr2.first!
print(what.id, what.front, what.score, what.back) // 1 yo 20 frf
请注意,我确实需要稍微更改您的代码;我将您的第二个CodingKeys更改为CodingKeys2,因为否则我无法编译您的代码。
class RegularCard : Card {
var back: String
init(id: Int, front : String, score: Int, back : String) {
self.back = back
super.init(id: id, front: front, score: score, cardType: .regular)
}
enum CodingKeys2 : String, CodingKey {
case back
case id
case front
case score
case cardType
}
override func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys2.self)
print("encoding Regular")
try super.encode(to: encoder)
try container.encode(back, forKey: .back)
}
required init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys2.self)
print("decoding regular")
back = try values.decode(String.self, forKey: .back)
try super.init(from: decoder)
}
}
不过,我确实明白你的意思;即使RegularCard进入,如果我们解码为Card,我们也无法将值恢复为RegularCard(不能向下转换(。我想,这正是可编码或泛型的本质。基本上,我的建议是,不要那样做。
然而,在这种情况下,你可以做的是尝试将其解码为RegularCard,如果这不起作用,则解码为Card。这样你总能得到正确的答案。
let card = Card(id: 2, front: "hoo", score: 10, cardType: .regular)
let reg = RegularCard(id: 1, front: "yo", score: 20, back: "frf")
let arr1 = [card]
let arr2 = [reg]
let data1 = try! JSONEncoder().encode(arr1)
let data2 = try! JSONEncoder().encode(arr2)
// first data1
do {
let result1 = try JSONDecoder().decode([RegularCard].self, from: data1)
print(result1)
} catch {
let result2 = try JSONDecoder().decode([Card].self, from: data1)
print(result2) // it's a Card
}
// now data2
do {
let result1 = try JSONDecoder().decode([RegularCard].self, from: data2)
print(result1) // it's a RegularCard
} catch {
let result2 = try JSONDecoder().decode([Card].self, from: data2)
print(result2)
}