2017-10-14 23 views
1

(Dies ist ein Follow-up von dieser Frage. Using Decodable protocol with multiples keys)Swift Dekodierbare Optional Key

Ich habe folgende Swift Code:

let additionalInfo = try values.nestedContainer(keyedBy: UserInfoKeys.self, forKey: .age) 
age = try additionalInfo.decodeIfPresent(Int.self, forKey: .realage) 

Ich weiß, wenn ich decodeIfPresent und don Wenn Sie eine optionale Variable haben, wird sie immer noch korrekt behandelt.

Zum Beispiel funktioniert das folgende JSON, um es mit dem obigen Code zu analysieren.

{ 
    "firstname": "Test", 
    "lastname": "User", 
    "age": {"realage": 29} 
} 

Und das folgende JSON funktioniert auch.

{ 
    "firstname": "Test", 
    "lastname": "User", 
    "age": {"notrealage": 30} 
} 

Aber das Folgende funktioniert nicht.

{ 
    "firstname": "Test", 
    "lastname": "User" 
} 

Wie kann ich alle 3 Beispiele arbeiten lassen? Gibt es etwas Ähnliches wie decodeIfPresent für nestedContainer?

Antwort

8

Sie können folgende KeyedDecodingContainer Funktion:

func contains(_ key: KeyedDecodingContainer.Key) -> Bool 

Gibt einen Bool Wert, der angibt, ob der Decoder ein Wert mit dem angegebenen Schlüssel zugeordnet enthält. Der Wert, der dem gegebenen Schlüssel zugeordnet ist, kann ein Nullwert sein, der für das Datenformat geeignet ist.

überprüfen, ob die "age" Schlüssel vor existieren den entsprechenden verschachtelten Container anfordert. Zum Beispiel:

struct Person: Decodable { 
    let firstName, lastName: String 
    let age: Int? 

    enum CodingKeys: String, CodingKey { 
     case firstName = "firstname" 
     case lastName = "lastname" 
     case age 
    } 

    enum AgeKeys: String, CodingKey { 
     case realAge = "realage" 
     case fakeAge = "fakeage" 
    } 

    init(from decoder: Decoder) throws { 
     let values = try decoder.container(keyedBy: CodingKeys.self) 
     self.firstName = try values.decode(String.self, forKey: .firstName) 
     self.lastName = try values.decode(String.self, forKey: .lastName) 

     if values.contains(.age) { 
      let age = try values.nestedContainer(keyedBy: AgeKeys.self, forKey: .age) 
      self.age = try age.decodeIfPresent(Int.self, forKey: .realAge) 
     } else { 
      self.age = nil 
     } 
    } 
} 
0

Können Sie versuchen, Ihren Beispiel-JSON in quicktype einzufügen, um zu sehen, welche Typen er enthält? Basierend auf Ihre Frage, klebte ich Ihre Proben und bekam:

struct UserInfo: Codable { 
    let firstname: String 
    let age: Age? 
    let lastname: String 
} 

struct Age: Codable { 
    let realage: Int? 
} 

machen UserInfo.age und Age.realage optionals funktioniert, wenn es das ist, was Sie erreichen wollen.

+1

Ich versuche, dies mit 1 Klasse/struct zu erreichen. Ich habe bestimmte Gründe dafür, es mit 1 Klasse/Struktur zu entwerfen. Siehe meine Frage und Antwort [hier] (https://stackoverflow.com/a/46737735/894067) für weitere Informationen. –

+0

Ah, ich sehe - ich muss der Antwort dort zustimmen, die ein "rohes" Modell vorschlägt, das der JSON-Struktur entspricht, die Sie Ihrem übergeordnete Modell mit dem eigenwilligen Verhalten zuordnen konnten, das Sie wünschen! Ich denke, das könnte viel einfacher zu verwalten und zu verstehen sein als die Implementierung von benutzerdefinierten Decodern, aber viel Glück auf jeden Fall! –

+0

So wie meine Daten in meinen Serverdateien strukturiert sind, macht es viel einfacher, benutzerdefinierte Decoder zu verwenden. Und nur durch mein Verständnis und Strukturieren ist es viel einfacher, es so zu machen. Vielleicht kann jemand eine Antwort geben, die zu dem passt, was ich will. Danke für deine Hilfe. –