Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

358
Visualizações
Swift Decode [String: Any]

So I have this API that returns a dictionary of [String: Any], I know that what comes as Any is Decodable or an array of Decodable however I can't for the life of me figure out how to take that dictionary and decode it to some struct:

What I have goes basically like this:

public func call<T: Codable> (completion handler: @escaping (T?) -> ()) {
    let promise = api.getPromise ()
    promise.done (on: DispatchQueue.main, { (results: [String:Any])
        let decodedResults:T? = results.decode (as: T.self) // <-- this is what I want
        handler (decodedResults)
    })
}

I've tried turning it to data and then decoding it with:

let values = results.compactMap { $0.value }
let data = JSONSerialization.data (withJSONObject: values, options: [])
let decodedResult = JSONDecoder().decode(T.self, from: data)

but it always fails with NSInvalidArgumentException, any idea how to get around this?

Another thing that I was trying to achieve but failed to do so is to turn values into a tuple, but for all I could find it's not possible to create tuples dynamically.

over 4 years ago · Santiago Trujillo
1 Respostas
Responde à pergunta

0

Decoders convert Data into Decodable values. They don't have anything to do with [String: Any] types or any other non-Data type. So if you want to run it through a decoder, you need to convert it to JSON encoded into Data.

If the [String: Any] results are exclusively JSONSerialization-safe types (arrays, dictionaries, strings, numbers, null), then JSONSerialization.data(withJSONObject:options:) would let you get back to data, so you can re-decode it. Your code doesn't just re-encode its results, it first turns it into an array:

let values = results.compactMap { $0.value }
let data = JSONSerialization.data (withJSONObject: values, options: [])

That's very strange. Do you really mean to create an array here and throw away the keys? I would then expect your JSONDecoder().decode() line to decode [T].self rather than T.self. So I would expect the following code (provided that your [String: Any] is JSON-safe):

public func call<T: Decodable>(completion handler: @escaping (T?) -> ()) {
    let promise = api.getPromise()
    promise.done(on: .main) { (results: [String:Any]) in
        guard JSONSerialization.isValidJSONObject(results) else {
            handler(nil)
            return
        }

        let data = JSONSerialization.data(withJSONObject: results)
        let decodedResults = try? JSONDecoder().decode(T.self, from: data)
        handler(decodedResults)
    }
}

In the comments you note that the decoded data (the [String: Any]) is not made of primitives. In that case it's not possible to re-encode it with JSONSerialization. You'll need to pass the [String: Any] to something that knows how to deal with it. For example:

protocol DictionaryDecodable {
    init?(dictionary: [String: Any])
}

public func call<T: DictionaryDecodable>(completion handler: @escaping (T?) -> ()) {
    let promise = api.getPromise ()
    promise.done(on: .main) { (results: [String:Any])
        handler(T.init(dictionary: results))
    }
}

Your types will need to implement an init?(dictionary:) that can decode their own values out of a [String: Any].

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda