StartPlayer
StartPlayer

Reputation: 495

Trying to write a generic function for parsing JSON into codable Structs

I'm currently parsing JSON like this

struct ExampleStruct : Codable {
     init() {

     }
     // implementation
}

if let jsonData = jsonString.data(using: .utf8) {
    do {
        let decoder = JSONDecoder()
        let object =  try decoder.decode(ExampleStruct.self, from: jsonData)
    } catch {
        print("Coding error - \(error)")
    }
}

This works fine, however I've been trying to learn about Generics over the weekend. I'm trying to write a method which I pass in a Codable struct type and a string of JSON which returns the object of type I want back.

I've tried the following :-

func getType<T>(_ anyType: T.Type, from jsonString:String) -> T? {

if let jsonData = jsonString.data(using: .utf8) {
    do {
        let decoder = JSONDecoder()
        let object =  try decoder.decode(anyType, from: jsonData)//Errors here
        return object as? T
        return nil
    } catch {
        print("Coding error - \(error)")
       return nil
    }
  }
return nil
}

and then when I want to do the above

 if let exampleStruct:ExampleStruct = getType(type(of: ExampleStruct()), from: jsonString) {
  print(exampleStruct)
 }

However on the let = object line I get the following errors

Cannot convert value of type 'T' (generic parameter of global function 'getType(:from:)') to expected argument type 'T' (generic parameter of instance method 'decode(:from:)')

and

In argument type 'T.Type', 'T' does not conform to expected type 'Decodable'

As I said I've just been trying to learn about generics this weekend but I've clearly hit a block in my understanding. Is there a fix for this, indeed is what I'm trying to do even possible or a good idea?

Upvotes: 1

Views: 2450

Answers (1)

vadian
vadian

Reputation: 285260

First of all it's highly recommended to hand over an error of a throwing function to the caller.
Second of all Data created from an UTF8 string can never fail.

You have to constrain the generic type to Decodable, it's not needed to pass the type as extra parameter.

Your function can be reduced to

func getType<T : Decodable>(from jsonString:String) throws -> T {
    let jsonData = Data(jsonString.utf8)
    return try JSONDecoder().decode(T.self, from: jsonData)
}

Upvotes: 7

Related Questions