Reputation: 1753
I was surprised recently to find that this:
protocol A: Encodable {}
class B: A {
var x = 3
}
class C: A {
var y = 4
}
let items: [A] = [B()]
let encoded = try JSONEncoder().encode(items)
Fails in Swift with:
Type 'any A' cannot conform to 'Encodable'
while this works:
let items: [B] = [B()]
let encoded = try JSONEncoder().encode(items)
Apparently the issue is that protocols do not conform to themselves. A workaround is provided in this answer.
I understand the reasoning and the workaround in the answers, but it is still quite inconvenient. Both of those answers are from ~2017; is there a cleaner way to solve this in swift 5?
Upvotes: 2
Views: 468
Reputation: 2794
Sample workaround :)
struct AnyEncodable: Encodable {
let item: any Encodable
func encode(to encoder: any Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(self.item)
}
}
let items: [A] = [B()]
let encoded = try JSONEncoder().encode(items.map { AnyEncodable(item: $0) })
Upvotes: 3
Reputation: 285072
encode(_:)
is a generic method which takes a concrete static type conforming to Encodable
. The generic design of the method is the reason why you cannot use the protocol itself. The compiler needs to know the structure of the static type to be able to synthesize the protocol method encode(_:)
.
Encode an array of items conforming to an Encodable protocol
is fine, but you are trying to
Encode an array of items being the Encodable protocol
which is impossible. This is valid since 2017 till today.
Upvotes: 0