问题
Consider the followings:
protocol A: Codable {
var b: B { get }
var num: Int { get }
}
protocol B: Codable {
var text: String { get }
}
struct C: A {
var b: B
var num: Int
}
The compiler gives two errors
- Type 'C' does not conform to protocol 'Decodable'
- Type 'C' does not conform to protocol 'Encodable'
However Both A and B are Codable. How to solve/avoid these errors?
Reference:
EDITED
As the auto-synthesis for Codable
not working, I manually implemented the required methods.
struct C: A {
var b: B
var num: Int
enum CodingKeys: String, CodingKey {
case b
case num
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(num, forKey: .num)
try container.encode(b, forKey: .b)
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
num = try values.decode(Int.self, forKey: .num)
b = try values.decode(B.self, forKey: .b)
}
}
and now it gives new errors
回答1:
A protocol doesn't tell the compiler how to encode/decode classes/structs that conforms to it. You need an implementation of the protocol for the compiler to fully understand how to init an instance of the C struct.
struct D: B {
var text: String
}
struct C: A {
var b: B
var num: Int
public init(from decoder: Decoder) throws {
b = D(text: " ")
num = 0
}
public func encode(to encoder: Encoder) throws {
}
}
Here is a more complete example in line with the second part of the question.
protocol A: Codable {
var b: B { get }
var num: Int { get }
}
protocol B: Codable {
var text: String { get }
}
struct D: B {
var text: String
}
struct C: A {
var b: B
var num: Int
enum CodingKeys: String, CodingKey {
case b
case num
}
public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
num = try values.decode(Int.self, forKey: .num)
let text = try values.decode(String.self, forKey: .b)
b = D(text: text)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(num, forKey: .num)
try container.encode(b.text, forKey: .b)
}
}
回答2:
You should implement init(from decoder: Decoder) and encode(to encoder: Encoder) in struct C because these are required for Codable (Decodable & Encodable) protocol use.
public init(from decoder: Decoder) throws{
}
public func encode(to encoder: Encoder) throws{
}
EDITED
In Swift protocol does not confirms to themselves so you should use associatedtype in Protocol A which confirms to Protocol B.
for better understanding of Protocol please read this answer.
https://stackoverflow.com/a/43408193/6303078
protocol B: Codable {
var text: String { get }
}
protocol A: Codable {
associatedtype CodableType : B
var b: CodableType { get }
var num: Int { get }
}
struct D: B {
var text: String
}
struct C<ElementType:B> : A{
typealias CodableType = ElementType
var b: CodableType
var num: Int
enum CodingKeys: String, CodingKey {
case b
case num
}
public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
num = try values.decode(Int.self, forKey: .num)
b = try values.decode(CodableType.self, forKey: .b)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(num, forKey: .num)
try container.encode(b, forKey: .b)
}
}
来源:https://stackoverflow.com/questions/49147559/fail-to-use-protocol-contains-protocol-adopting-codable