2017-08-17 6 views
2

J'essaie d'utiliser le nouveau décodage JSON de Swift 4 pour analyser JSON à partir d'un serveur distant. Le schéma JSON inclut des valeurs d'énumération, dont certaines dont je n'ai pas réellement besoin pour mes besoins et que j'aimerais ignorer. De plus, j'aimerais aussi être suffisamment robuste pour que lorsque le schéma JSON change, je puisse toujours lire autant de données que possible. Le problème est que lorsque j'essaye d'analyser un tableau de n'importe quoi contenant enums, à moins que chaque valeur enum corresponde exactement aux littéraux de mon énumérateur, le décodeur lève une exception plutôt que d'ignorer les données qu'il ne peut pas analyser.Un moyen pour que Swift 4 JSON Decoder ne se lance pas sur un tableau contenant une valeur enum non reconnue?

Voici un exemple simple:

enum Size: String, Codable { 
    case large = "large" 
    case small = "small" 
} 

enum Label: String, Codable { 
    case kitchen = "kitchen" 
    case bedroom = "bedroom" 
    case livingRoom = "living room" 
} 

struct Box: Codable { 
    var contents: String 
    var size: Size 
    var labels: [Label] 
} 

Quand je parse des données qui se conforme complètement à ma taille ENUM, j'obtenir les résultats escomptés:

let goodJson = """ 
[ 
    { 
    "contents": "pillows", 
    "size": "large", 
    "labels": [ 
     "bedroom" 
    ] 
    }, 
    { 
    "contents": "books", 
    "size": "small", 
    "labels": [ 
     "bedroom", 
     "living room" 
    ] 
    } 
] 
""".data(using: .utf8)! 

let goodBoxes = try? JSONDecoder().decode([Box?].self, from: goodJson) 
// returns [{{contents "pillows", large, [bedroom]}},{{contents "books", small, [bedroom, livingRoom]}}] 

Cependant, s'il y a des contenus qui n » t conforme à l'énumération, le décodeur jette une exception et je ne reçois rien en retour.

let badJson = """ 
[ 
    { 
    "contents": "pillows", 
    "size": "large", 
    "labels": [ 
     "bedroom" 
    ] 
    }, 
    { 
    "contents": "books", 
    "size": "small", 
    "labels": [ 
     "bedroom", 
     "living room", 
     "office" 
    ] 
    }, 
    { 
    "contents": "toys", 
    "size": "medium", 
    "labels": [ 
     "bedroom" 
    ] 
    } 
] 
""".data(using: .utf8)! 

let badBoxes = try? JSONDecoder().decode([Box?].self, from: badJson) // returns nil 

Idéalement, dans ce cas, je voudrais revenir les 2 articles où la taille est conforme à la « petite » ou « grand » et la deuxième blessure de l'élément ont les 2 étiquettes valides, « chambre » et « vie chambre". Si j'implémente mon propre init (à partir de: décodeur) pour Box, je pourrais décoder moi-même les étiquettes et en éliminer toutes celles qui ne sont pas conformes à mon énumération. Cependant, je ne peux pas comprendre comment décoder un type [Box] pour ignorer les cases invalides sans implémenter mon propre Decoder et analyser le JSON moi-même, ce qui va à l'encontre de l'objectif d'utiliser Codable.

Des idées?

+0

J'ai un cas similaire, où je veux juste ignorer les éléments de tableau invalides et ne veut pas que l'analyseur échoue sur tout le tableau. Est-ce qu'il n'y a vraiment aucun moyen d'ignorer les éléments invalides, au lieu de complètement "jeter" le tableau et échouer l'analyse complète? : -/ – d4Rk

+0

Comparez https://stackoverflow.com/q/46344963/2976878 – Hamish

Répondre

0

J'admettrai que ce n'est pas la plus jolie solution mais c'est ce que j'ai imaginé et je pensais partager. J'ai créé une extension sur Array qui permet cela. Le plus gros problème est que vous devez décoder puis encoder les données JSON à nouveau.

extension Array where Element: Codable { 
    public static func decode(_ json: Data) throws -> [Element] { 
     let jsonDecoder = JSONDecoder() 
     var decodedElements: [Element] = [] 
     if let jsonObject = (try? JSONSerialization.jsonObject(with: json, options: [])) as? Array<Any> { 
      for json in jsonObject { 
       if let data = try? JSONSerialization.data(withJSONObject: json, options: []), let element = (try? jsonDecoder.decode(Element.self, from: data)) { 
        decodedElements.append(element) 
       } 
      } 
     } 
     return decodedElements 
    } 
} 

Vous pouvez utiliser cette extension avec tout ce qui est conforme à Codable et devrait résoudre votre problème.

[Box].decode(json) 

Malheureusement, je ne vois pas comment cela va résoudre le problème avec les étiquettes étant incorrecte et vous devrez faire comme vous le dites et passer outre init(from: Decoder) pour vous assurer que vos étiquettes sont valides.