Reputation: 10887
I'm working on a small struct that handles the parsing of JSON. Up until now it is all working except I am wanting to pass a custom struct as a structure to use on the decode in JSONDecoder().decode(type.self, from: data)
but this is throwing the following error:
Cannot convert value of type 'Codable' (aka 'Decodable & Encodable') to expected argument type 'T.Type'
private func parseJson(data: Data, type: Codable) -> Codable? {
do {
let decoded = try JSONDecoder().decode(type.self, from: data)
return decoded
} catch {
print("JSON decode error: \(error.localizedDescription)")
}
return nil
}
Is there a way that I can pass a struct into this method to use as the type for the decode()
function? If I directly set the type I'm trying to pass into the function on the decode() function the code works as expected, it only errors out when I attempt to pass it in.
Upvotes: 6
Views: 3626
Reputation: 236568
What you need is a generic method:
private func parseJson<T: Decodable>(data: Data, type: T.Type) -> T? {
do {
return try JSONDecoder().decode(type.self, from: data)
} catch {
print("JSON decode error:", error)
return nil
}
}
You can also omit the type and explicitly set the type of the resulting object:
private func parseJson<T: Decodable>(data: Data) -> T? {
do {
return try JSONDecoder().decode(T.self, from: data)
} catch {
print("JSON decode error:", error)
return nil
}
}
Playground testing:
struct User: Codable {
let id: Int
let name: String
}
let user: User = .init(id: 2, name: "abc")
let userData = try! JSONEncoder().encode(user)
let decodedUser: User = parseJson(data: userData)!
decodedUser.name // "abc"
Note: I am returning optional types but you should definitely make your methods throw and return a non optional as you can see below where I am extending Data:
extension Data {
func decodedObject<T: Decodable>() throws -> T {
try JSONDecoder().decode(T.self, from: self)
}
}
do {
let decodedUser: User = try userData.decodedObject()
print(decodedUser.name) // "abc"
} catch {
print(error)
}
Upvotes: 7