With Codable
, I am able to create the following extension
extension Decodable {
public static func decode(data: Data, decoder: JSONDecoder = .default) -> Self? {
do {
return try decoder.decode(self, from: data)
} catch let error as NSError {
CodableKit.log(message: "\(error.userInfo)")
return nil
}
}
}
and use it on both single objects and array types, for example
let person = Person.decode(data: personData) // single
let people = [Person].decode(data: peopleData) // array
The 2 lines above compile without issues.
Now, I want to create a new protocol similar to Codable
public typealias JsonCodable = JsonDecodable & JsonEncodable
public protocol JsonDecodable: Decodable {
static func decode(data: Data?, decoder: JSONDecoder) -> Self?
}
extension JsonDecodable {
static func decode(data: Data?, decoder: JSONDecoder) -> Self? {
....
}
}
When I use try to use JsonDecodable
the same way I do with Codable
, i get the following compiler error
Type '[Person]' has no member 'decode';
let person = Person.decode(data: personData) // this works
let people = [Person].decode(data: peopleData) // this does not
How can I get JsonDecodable
to decode into an array of a model the same way I can when extending Codable
?
The error message might be more useful if it used the unsugared typename:
Type 'Array<Person>' has no member 'decode';
Person
may conform to your protocol, but Array
does not. Swift explicitly declares that Array
s are Decodable
if their elements are. You just need to do the same:
extension Array : JsonDecodable where Element : JsonDecodable {
static func decode(data: Data?, decoder: JSONDecoder) -> Self? {
// Decode each element and return an array
}
}
This uses a feature called "Conditional Conformance", which allows containers generally to conform to a protocol if the type they hold also does.