2017-07-13 17 views
2

I-Struktur wie dieses:Convert erhalten Int Dekodieren von JSON in Bool Kodierbare mit

struct JSONModelSettings { 
    let patientID : String 
    let therapistID : String 
    var isEnabled : Bool 

    enum CodingKeys: String, CodingKey { 
     case settings // The top level "settings" key 
    } 

    // The keys inside of the "settings" object 
    enum SettingsKeys: String, CodingKey { 
     case patientID = "patient_id" 
     case therapistID = "therapist_id" 
     case isEnabled = "is_therapy_forced" 
    } 
} 

extension JSONModelSettings: Decodable { 
    init(from decoder: Decoder) throws { 

     // Extract the top-level values ("settings") 
     let values = try decoder.container(keyedBy: CodingKeys.self) 

     // Extract the settings object as a nested container 
     let user = try values.nestedContainer(keyedBy: SettingsKeys.self, forKey: .settings) 

     // Extract each property from the nested container 
     patientID = try user.decode(String.self, forKey: .patientID) 
     therapistID = try user.decode(String.self, forKey: .therapistID) 
     isEnabled = try user.decode(Bool.self, forKey: .isEnabled) 
    } 
} 

und JSON in diesem Format (Struktur verwendeten Schlüssel ziehen aus ohne zusätzliche Wrapper Einstellung):

{ 
    "settings": { 
    "patient_id": "80864898", 
    "therapist_id": "78920", 
    "enabled": "1" 
    } 
} 

Frage ist, wie kann ich konvertieren "isEnabled" zu Bool, (1 oder 0 von API bekommen) Wenn ich versuche zu antworten Antwort im bekommen Fehler: "Erwartet, Bool zu dekodieren, aber eine Zahl stattdessen gefunden."

+0

Warum wrappen Sie 'forKey: .isEnabled 'nicht innerhalb einer Funktion, die ein bool' true' für eine 1 und 'false' für 0 zurückgibt? – Fabien

Antwort

2

Mein Vorschlag ist: kämpfe nicht gegen den JSON. Holen Sie es so schnell wie möglich in einen Swift-Wert und machen Sie Ihre Manipulation dort.

Sie können eine private interne Struktur definieren, die entschlüsselten Daten zu halten, wie folgt aus:

struct JSONModelSettings { 
    let patientID : String 
    let therapistID : String 
    var isEnabled : Bool 
} 

extension JSONModelSettings: Decodable { 
    // This struct stays very close to the JSON model, to the point 
    // of using snake_case for its properties. Since it's private, 
    // outside code cannot access it (and no need to either) 
    private struct JSONSettings: Decodable { 
     var patient_id: String 
     var therapist_id: String 
     var enabled: String 
    } 

    private enum CodingKeys: String, CodingKey { 
     case settings 
    } 

    init(from decoder: Decoder) throws { 
     let container = try decoder.container(keyedBy: CodingKeys.self) 
     let settings = try container.decode(JSONSettings.self, forKey: .settings) 
     patientID  = settings.patient_id 
     therapistID = settings.therapist_id 
     isEnabled  = settings.enabled == "1" ? true : false 
    } 
} 

Andere JSON-Mapping-Frameworks, wie ObjectMapper Sie eine Funktion der Codierung umwandeln befestigen können/Decodierungsprozess. Es sieht aus wie Codable hat keine Äquivalenz für jetzt.

2

Decode als String und wandeln sie dann zu Bool, nur ein paar Zeilen von Code zu modifizieren: (. "0" ist ein JSON-String, und kann nicht als Int decodiert werden)

struct JSONModelSettings { 
    let patientID : String 
    let therapistID : String 
    var isEnabled : Bool 

    enum CodingKeys: String, CodingKey { 
     case settings // The top level "settings" key 
    } 

    // The keys inside of the "settings" object 
    enum SettingsKeys: String, CodingKey { 
     case patientID = "patient_id" 
     case therapistID = "therapist_id" 
     case isEnabled = "enabled"//### "is_therapy_forced"? 
    } 
} 

extension JSONModelSettings: Decodable { 
    init(from decoder: Decoder) throws { 

     // Extract the top-level values ("settings") 
     let values = try decoder.container(keyedBy: CodingKeys.self) 

     // Extract the settings object as a nested container 
     let user = try values.nestedContainer(keyedBy: SettingsKeys.self, forKey: .settings) 

     // Extract each property from the nested container 
     patientID = try user.decode(String.self, forKey: .patientID) 
     therapistID = try user.decode(String.self, forKey: .therapistID) 

     //### decode the value for "enabled" as String 
     let enabledString = try user.decode(String.self, forKey: .isEnabled) 
     //### You can throw type mismatching error when `enabledString` is neither "0" or "1" 
     if enabledString != "0" && enabledString != "1" { 
      throw DecodingError.typeMismatch(Bool.self, DecodingError.Context(codingPath: user.codingPath + [SettingsKeys.isEnabled], debugDescription: "value for \"enabled\" needs to be \"0\" or \"1\"")) 
     } 
     //### and convert it to Bool 
     isEnabled = enabledString != "0" 
    } 
}