在 Swift 中,只要繼承 Codable Protocol,就可以將 struct、enum 或是 class 做 Encoder,並變成一個 Json 物件或是 Dictionary,然而,如果 class 有使用繼承的話,事情就不是想的這麼簡單了。
![[Swift] class 在繼承時如何正確使用 Encoder 1 swift 1](https://www.inote.tw/wp-content/uploads/2020/02/swift-1.png)
以下列例子為例,我們預期得到的答案會是「{“name”:”Sparky”,”age”:5,”breed”:”Labrador”}」,但是實際跑起來,卻是「{“name”:”Sparky”,”age”:5}」,為什麼呢?
class Animal: Codable {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
func speak() {
print("\(name) says something")
}
}
class Dog: Animal {
var breed: String
init(name: String, age: Int, breed: String) {
self.breed = breed
super.init(name: name, age: age)
}
required init(from decoder: Decoder) throws {
fatalError("init(from:) has not been implemented")
}
override func speak() {
print("\(name) barks")
}
}
let dog = Dog(name: "Sparky", age: 5, breed: "Labrador")
// 使用父類別的 JSONEncoder
let encoder = JSONEncoder()
let jsonData = try! encoder.encode(dog)
let jsonString = String(decoding: jsonData, as: UTF8.self)
print(jsonString)
原來是因為 Animal 實做 Codable,所以 Swift 只認得 Animal 的參數,並且將其 Encode,那麼我們如何將 Dog 的參數也 Encode 呢?很簡單,只要在 Dog 類別加入以下的程式碼。
private enum CodingKeys: String, CodingKey {
case breed
}
override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(breed, forKey: .breed)
}
原始的程式如下,你會發現 Dog 也被 Encode 了
class Animal: Codable {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
func speak() {
print("\(name) says something")
}
}
class Dog: Animal {
var breed: String
init(name: String, age: Int, breed: String) {
self.breed = breed
super.init(name: name, age: age)
}
required init(from decoder: Decoder) throws {
fatalError("init(from:) has not been implemented")
}
private enum CodingKeys: String, CodingKey {
case breed
}
override func encode(to encoder: Encoder) throws {
try super.encode(to: encoder)
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(breed, forKey: .breed)
}
override func speak() {
print("\(name) barks")
}
}
let dog = Dog(name: "Sparky", age: 5, breed: "Labrador")
// 使用父類別的 JSONEncoder
let encoder = JSONEncoder()
let jsonData = try! encoder.encode(dog)
let jsonString = String(decoding: jsonData, as: UTF8.self)
print(jsonString)