我有一个从可编码继承的协议
protocol OrderItem:Codable {
var amount:Int{get set}
var isPaid:Bool{get set}
}
Run Code Online (Sandbox Code Playgroud)
结构符合此协议
struct ProductItem:OrderItem {
var amount = 0
var isPaid = false
var price = 0.0
}
Run Code Online (Sandbox Code Playgroud)
然而,当我把这个结构放入可编码的结构时,我得到了错误
struct Order:Codable {
var id:String
var sn:String = ""
var items:[OrderItem] = []
var createdAt:Int64 = 0
var updatedAt:Int64 = 0
}
Run Code Online (Sandbox Code Playgroud)
错误是
Type 'Order' does not conform to protocol 'Encodable'
Type 'Order' does not conform to protocol 'Decodable'
Run Code Online (Sandbox Code Playgroud)
但如果我更改项目:[OrderItem]到项目:[ProductItem],一切正常!
我该如何解决这个问题?
你不能这样做,因为协议只陈述你必须做的事情.因此,当您遵循协议X
时Codable
,它只意味着符合的任何类型也X
必须符合,Codable
但它不会提供所需的实现.您可能感到困惑,因为Codable
当您的所有类型都已经存在时,您不需要执行任何操作Codable
.如果Codable
要求你说实现一个被调用的函数myFunction
,你OrderItem
就不会缺少该函数的实现.
以下是您可以做的事情:
struct Order<T: OrderItem>: Codable {
var id:String
var sn:String = ""
var items: [T] = []
var createdAt:Int64 = 0
var updatedAt:Int64 = 0
}
Run Code Online (Sandbox Code Playgroud)
你现在说这items
是一个符合的泛型类型OrderItem
.
值得一提的是,如果您有一个数组的属性并且类型是一个协议:let arrayProtocol: [MyProtocol]
并且该数组包含多个都符合 的类型MyProtocol
,则您必须实现自己的init(from decoder: Decoder) throws
来获取值并func encode(to encoder: Encoder) throws
对其进行编码。
例如:
protocol MyProtocol {}
struct FirstType: MyProtocol {}
struct SecondType: MyProtocol {}
struct CustomObject: Codable {
let arrayProtocol: [MyProtocol]
enum CodingKeys: String, CodingKey {
case firstTypeKey
case secondTypeKey
}
}
Run Code Online (Sandbox Code Playgroud)
所以我们的解码看起来像这样:
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
// FirstType conforms to MyProtocol
let firstTypeArray = try values.decode([FirstType].self, forKey: .firstTypeKey)
// SecondType conforms to MyProtocol
let secondTypeArray = try values.decode([SecondType].self, forKey: .secondTypeKey)
// Our array is finally decoded
self.arrayProtocol: [MyProtocol] = firstTypeArray + secondTypeArray
}
Run Code Online (Sandbox Code Playgroud)
与编码相同,我们需要在编码之前转换为实际类型:
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
let firstActualTypeArray = arrayProtocol.compactMap{$0 as? FirstType}
let secondActualTypeArray = arrayProtocol.compactMap{$0 as? SecondType}
try container.encode(firstActualTypeArray, forKey: .firstTypeKey)
try container.encode(secondActualTypeArray, forKey: .secondTypeKey)
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1114 次 |
最近记录: |