Saltar al contenido

Cómo decodificar una propiedad con el tipo de diccionario JSON en Swift [45] protocolo decodificable

Comprende el código bien previamente a usarlo a tu trabajo y si tquieres aportar algo puedes decirlo en los comentarios.

Solución:

Con algo de inspiración de esta esencia que encontré, escribí algunas extensiones para UnkeyedDecodingContainer y KeyedDecodingContainer. Puede encontrar un enlace a mi esencia aquí. Al usar este código, ahora puede decodificar cualquier Array o Dictionary con la sintaxis familiar:

let dictionary: [String: Any] = try container.decode([String: Any].self, forKey: key)

o

let array: [Any] = try container.decode([Any].self, forKey: key)

Editar: Hay una salvedad que he encontrado que es decodificar un array de diccionarios [[String: Any]] La sintaxis requerida es la siguiente. Es probable que desee lanzar un error en lugar de forzar el lanzamiento:

let items: [[String: Any]] = try container.decode(Array.self, forKey: .items) as! [[String: Any]]

EDITAR 2: Si simplemente desea convertir un archivo completo en un diccionario, es mejor que se quede con la API de JSONSerialization, ya que no he descubierto una manera de extender JSONDecoder para decodificar directamente un diccionario.

guard let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else 
  // appropriate error handling
  return

Las extensiones

// Inspired by https://gist.github.com/mbuchetics/c9bc6c22033014aa0c550d3b4324411a

struct JSONCodingKeys: CodingKey 
    var stringValue: String

    init?(stringValue: String) 
        self.stringValue = stringValue
    

    var intValue: Int?

    init?(intValue: Int) 
        self.init(stringValue: "(intValue)")
        self.intValue = intValue
    



extension KeyedDecodingContainer 

    func decode(_ type: Dictionary.Type, forKey key: K) throws -> Dictionary 
        let container = try self.nestedContainer(keyedBy: JSONCodingKeys.self, forKey: key)
        return try container.decode(type)
    

    func decodeIfPresent(_ type: Dictionary.Type, forKey key: K) throws -> Dictionary? 
        guard contains(key) else  
            return nil
        
        guard try decodeNil(forKey: key) == false else  
            return nil 
        
        return try decode(type, forKey: key)
    

    func decode(_ type: Array.Type, forKey key: K) throws -> Array 
        var container = try self.nestedUnkeyedContainer(forKey: key)
        return try container.decode(type)
    

    func decodeIfPresent(_ type: Array.Type, forKey key: K) throws -> Array? 
        guard contains(key) else 
            return nil
        
        guard try decodeNil(forKey: key) == false else  
            return nil 
        
        return try decode(type, forKey: key)
    

    func decode(_ type: Dictionary.Type) throws -> Dictionary 
        var dictionary = Dictionary()

        for key in allKeys 
            if let boolValue = try? decode(Bool.self, forKey: key) 
                dictionary[key.stringValue] = boolValue
             else if let stringValue = try? decode(String.self, forKey: key) 
                dictionary[key.stringValue] = stringValue
             else if let intValue = try? decode(Int.self, forKey: key) 
                dictionary[key.stringValue] = intValue
             else if let doubleValue = try? decode(Double.self, forKey: key) 
                dictionary[key.stringValue] = doubleValue
             else if let nestedDictionary = try? decode(Dictionary.self, forKey: key) 
                dictionary[key.stringValue] = nestedDictionary
             else if let nestedArray = try? decode(Array.self, forKey: key) 
                dictionary[key.stringValue] = nestedArray
            
        
        return dictionary
    


extension UnkeyedDecodingContainer 

    mutating func decode(_ type: Array.Type) throws -> Array 
        var array: [Any] = []
        while isAtEnd == false 
            // See if the current value in the JSON array is `null` first and prevent infite recursion with nested arrays.
            if try decodeNil() 
                continue
             else if let value = try? decode(Bool.self) 
                array.append(value)
             else if let value = try? decode(Double.self) 
                array.append(value)
             else if let value = try? decode(String.self) 
                array.append(value)
             else if let nestedDictionary = try? decode(Dictionary.self) 
                array.append(nestedDictionary)
             else if let nestedArray = try? decode(Array.self) 
                array.append(nestedArray)
            
        
        return array
    

    mutating func decode(_ type: Dictionary.Type) throws -> Dictionary 

        let nestedContainer = try self.nestedContainer(keyedBy: JSONCodingKeys.self)
        return try nestedContainer.decode(type)
    

También jugué con este problema y finalmente escribí una biblioteca simple para trabajar con tipos “JSON genéricos”. (Donde “genérico” significa “sin estructura conocida de antemano”.) El punto principal es representar el JSON genérico con un tipo concreto:

public enum JSON 
    case string(String)
    case number(Float)
    case object([String:JSON])
    case array([JSON])
    case bool(Bool)
    case null

Este tipo puede implementar Codable y Equatable.

Puede crear una estructura de metadatos que confirme Decodable protocolo y uso JSONDecoder clase para crear objetos a partir de datos utilizando el método de decodificación como se muestra a continuación

let json: [String: Any] = [
    "object": "customer",
    "id": "4yq6txdpfadhbaqnwp3",
    "email": "[email protected]",
    "metadata": [
        "link_id": "linked-id",
        "buy_count": 4
    ]
]

struct Customer: Decodable 
    let object: String
    let id: String
    let email: String
    let metadata: Metadata


struct Metadata: Decodable 
    let link_id: String
    let buy_count: Int


let data = try JSONSerialization.data(withJSONObject: json, options: .prettyPrinted)

let decoder = JSONDecoder()
do 
    let customer = try decoder.decode(Customer.self, from: data)
    print(customer)
 catch 
    print(error.localizedDescription)

Reseñas y calificaciones del artículo

Si sostienes algún titubeo y capacidad de acrecentar nuestro tutorial te insinuamos realizar una ilustración y con placer lo observaremos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *