Search code examples
jsonswiftdecodecodable

decode JSON string to class object


 private func createWeatherObjectWith(json: Data, x:Any.Type ,completion: @escaping (_ data: Any?, _ error: Error?) -> Void) {
        do {
            let decoder = JSONDecoder()
            decoder.keyDecodingStrategy = .convertFromSnakeCase
            let weather = try decoder.decode(x.self, from: json)
            return completion(weather, nil)
        } catch let error {
            print("Error creating current weather from JSON because: \(error.localizedDescription)")
            return completion(nil, error)
        }
    }

Here I write above code to decode JSON string to class object by passing class type. But it gives the following error

Cannot invoke 'decode' with an argument list of type '(Any.Type, from: Data)'

Solution

  • If you are trying to decode any type of object then use these technique

    1. Generics function

    private func createWeatherObjectWith<T: Decodable>(json: Data, Object:T.Type ,completion: @escaping (_ data: T?, _ error: Error?) -> Void) {
        do {
            let decoder = JSONDecoder()
            decoder.keyDecodingStrategy = .convertFromSnakeCase
            let weather = try decoder.decode(T.self, from: json)
            return completion(weather, nil)
        } catch let error {
            return completion(nil, error)
        }
    }
    

    2. Extend Decodable

    extension Decodable {
        static func map(JSONString:String) -> Self? {
            do {
                let decoder = JSONDecoder()
                decoder.keyDecodingStrategy = .convertFromSnakeCase
                return try decoder.decode(Self.self, from: Data(JSONString.utf8))
            } catch let error {
                print(error)
                return nil
            }
        }
    }
    

    Use:

    let user = User.map(JSONString:"your JSON string")
    let users = [User].map(JSONString:"your JSON string")