2017-10-19 15 views
4

Si j'ai un struct conforme au protocole Codable comme ceci:dictionnaire personnalisé encodeur et décodeur pour le protocole codable à Swift 4

enum AnimalType: String, Codable { 
    case dog 
    case cat 
    case bird 
    case hamster 
} 

struct Pet: Codable { 
    var name: String 
    var animalType: AnimalType 
    var age: Int 
    var ownerName: String 
    var pastOwnerName: String? 
} 

Comment puis-je créer un codeur & un décodeur qui code/décode vers/depuis une instance de type Dictionary<String, Any?> comme ça?

let petDictionary: [String : Any?] = [ 
    "name": "Fido", 
    "animalType": "dog", 
    "age": 5, 
    "ownerName": "Bob", 
    "pastOwnerName": nil 
] 
let decoder = DictionaryDecoder() 
let pet = try! decoder.decode(Pet.self, for: petDictionary) 

NB: Je suis conscient qu'il est possible d'utiliser les JSONEncoder et JSONDecoder cours avant de lancer le résultat à un objet dictionnaire, mais je ne veux pas que pour des raisons d'efficacité.

La bibliothèque standard Swift est livré avec la JSONEncoder et JSONDecoder ainsi que les PListEncoder et PListDecoder les classes dès la sortie de la boîte qui se conforment aux Encoder et Decoder protocoles respectivement.

Mon problème est que je n'ai aucune idée comment mettre en œuvre ces protocoles pour mon codeur personnalisés et des classes décodeur:

class DictionaryEncoder: Encoder { 

    var codingPath: [CodingKey] 

    var userInfo: [CodingUserInfoKey : Any] 

    func container<Key>(keyedBy type: Key.Type) -> KeyedEncodingContainer<Key> where Key : CodingKey { 

    } 

    func unkeyedContainer() -> UnkeyedEncodingContainer { 

    } 

    func singleValueContainer() -> SingleValueEncodingContainer { 

    } 
} 
class DictionaryDecoder: Decoder { 

    var codingPath: [CodingKey] 

    var userInfo: [CodingUserInfoKey : Any] 

    func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> where Key : CodingKey { 

    } 

    func unkeyedContainer() throws -> UnkeyedDecodingContainer { 

    } 

    func singleValueContainer() throws -> SingleValueDecodingContainer { 

    } 
} 

Étant donné que Swift est open source, il est possible de voir le code source les classes JSONEncoder et PListEncoder dans la bibliothèque standard, mais les fichiers sources sont énormes et difficiles à comprendre en raison du manque de documentation à part quelques commentaires.

+0

Si vous ne voulez pas utiliser JSONDecoder alors pourquoi implémenter les protocoles Codable? – NSAdi

+1

Le protocole Codable est généralisé/générique et peut être utilisé pour représenter des structures de données externes avec des types Swift natifs. La bibliothèque standard Swift dispose des protocoles 'Encoder' et' Decoder' que vous pouvez implémenter pour créer votre propre codeur et décodeur personnalisé pour le protocole Codable. La bibliothèque standard Swift est livré avec deux paires de tels codeur/décodeur de: https://github.com/apple/swift/blob/master/stdlib/public/SDK/Foundation/PlistEncoder.swift https: // GitHub. com/apple/swift/blob/maître/stdlib/public/SDK/Foundation/JSONEncoder.swift –

+1

Mon problème est que le code là-bas est beaucoup trop complexe et en dehors des commentaires dans la base de code, il n'y a pas de documentation qui explique comment vous pouvez implémentez votre propre codeur et décodeur personnalisé qui se conforment respectivement aux protocoles 'Encoder' et' Decoder'. –

Répondre

1

Si vous regardez la mise en œuvre de JSONDecoder (here), vous verrez que c'est un processus en deux étapes: 1. Utilisez JSONSerialization pour convertir le Data dans un dictionnaire JSON, puis 2. créer une instance d'un interne classe _JSONDecoder pour faire le dictionnaire ->Codable conversion d'objet.

Il est some discussion on the Swift forums d'exposer éventuellement les types internes, et l'équipe Swift peut faire quelque chose à ce sujet à l'avenir. Quelqu'un a également offert un cadre tiers pour faire ce que vous voulez.