decode JSON string to class object
Asked Answered
I

3

9
 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)'
Inpour answered 19/11, 2018 at 2:22 Comment(2)
I think you need to convert it into object instead of decodingWebbed
You should provide the full code you try to run including the JSON (in a Playground compatible way) and your Codable class/struct. That will enable us to help you properly. Please edit your question and do not post code in comments in order to clarify.Chara
M
7

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")
Magician answered 19/11, 2018 at 2:56 Comment(4)
Never call localizedDescription in a Codable catch block. Don't do that. You will get a generic error message rather than the real Codable error. Print always the entire error instance.Hesson
@Hesson Better if use error exceptional handling rather than error codes.Magician
Codable errors are very descriptive, there are no codes, the most significant information is in the context property.Hesson
Was not focusing on debugging part of this, but I agree with you that error is better for error handling and debugging rather than the localized description.Magician
B
1

Trying to decode any type of Object to String in Swift 4.1

func convertAnyObjectToJSONString(from object:Any) -> String? {

    guard let data = try? JSONSerialization.data(withJSONObject: object, options: []) else { 

        return nil 
    }

    return String(data: data, encoding: String.Encoding.utf8) 
}
Bestraddle answered 19/11, 2018 at 6:54 Comment(1)
Invalid top-level type in JSON writeJobye
W
1

Simple explanation. Decode "from string" rather than "from data".

Somewhat confusingly, you "normally" decode from data, not from a string:

let result = try? JSONDecoder().decode(YourClass.self, from: data))

Sometimes, unusually, you will have an actual string, rather than data.

If so:

let result = try? JSONDecoder().decode(YourClass.self, from: Data(someString.utf8)))

and that's it.

Whenever you need to convert a string to data, these days it's just

Data(someString.utf8)
Warden answered 27/6, 2023 at 16:32 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.