Codierbar gegen ObjectMapper

Foto von https://unsplash.com/photos/_rNVw54xZZg

Ich habe kürzlich mit Swifts neuem Codable-Protokoll experimentiert, um JSON, das von einem Remotedienst abgerufen wurde, einem Swift-Modellobjekt zuzuordnen.

Für einige Hintergrundinformationen wurde Codable in Swift 4 hinzugefügt, um zu ermöglichen, dass Objekte sich selbst in eine externe Darstellung und aus dieser heraus konvertieren. Codable selbst ist nur ein typealias von Decodable und Encodable.

In diesem Beitrag werde ich mich auf den dekodierbaren Teil konzentrieren, da es sich um die Konvertierung von einer entfernten JSON-Repräsentation handelt, die mich interessiert.

Vergleich

Ich habe ObjectMapper in der Vergangenheit ausgiebig genutzt, aber da Codable jetzt in Swift integriert ist, wollte ich einen Vergleich der beiden durchführen. Die Funktionen, die ich vergleichen möchte, sind:

  • Validierung ️
  • Benutzerdefinierte Transformation (Zuordnung zu benutzerdefinierten Typen, z. B. Zuordnung einer JSON-Zeichenfolge zu einem regulären Ausdruck)
  • Fehlerbehandlung

Die Daten, die ich analysieren werde, sind echte Konfigurationsdaten, die wir remote für die BBC Sport-App abrufen

Es handelt sich um eine relativ einfache JSON-Struktur, die jedoch einige reguläre Ausdrücke enthält, die NSRegularExpression und nicht einem String zugeordnet werden sollen

ObjectMapper

Folgende Strukturen sind erforderlich, um dieses JSON-Modell mit ObjectMapper abzubilden.

Die Stucts entsprechen alle dem ImmutableMappable-Protokoll. Dies bedeutet, dass sie einen Konstruktor benötigen, der ein Map-Objekt verwendet und einen Fehler ausgibt, wenn das Mapping fehlschlägt.

Validierung

Zur Durchführung der Validierung können Sie Optionals verwenden. In diesem Beispiel haben wir entschieden, dass die App ohne diese E-Mail-Adressen funktionieren kann, sodass die E-Mails optional sind. map.values ​​("E-Mails") gibt einen Fehler aus, wenn der Schlüssel nicht vorhanden ist oder nicht in den richtigen Typ umgewandelt werden kann. Wir nutzen versuchen? um diesen Fehler zu erfassen und ihn im Fehlerfall in einen Nullwert umzuwandeln.

Wenn wir beschließen, dass eine bestimmte Eigenschaft erforderlich ist, markieren wir sie nicht als optional und lassen zu, dass sich der Fehler ausbreitet.

Insgesamt ist die Validierung mit ImmutableMappable sehr einfach

Möglicherweise haben Sie bemerkt, dass in diesen Aufruf map.value ("regex", RegexTransformer ()) ein zusätzliches Argument eingefügt wurde, mit dessen Hilfe die benutzerdefinierte Umwandlung des Strings in einen NSRegularExpression-Befehl zum nächsten Punkt führt.

Benutzerdefinierte Transformation

ObjectMapper unterstützt benutzerdefinierte Transformationen von Anfang an und ist sehr einfach.

Hier implementieren wir nur das TransformType-Protokoll und die zugehörige transformFromJSON-Methode. Das nimmt einen Typ auf und den wir in String umwandeln und dann sicher probieren? Konvertieren der Zeichenfolge in eine NSRegularExpression.

Dieser Transformator kann dann überall wiederverwendet werden

Fehlerbehandlung

Zum Testen der Fehlerbehandlung verwende ich eine JSON-Datei mit dem fehlenden Ausgabeschlüssel.

Wenn dies über ObjectMapper ausgeführt wird, wird eine hilfreiche Fehlermeldung ausgegeben.

Beim Mapping ist ein Fehler aufgetreten.
- Grund: Kann nicht in 'String' umgewandelt werden
- Ort: Config.init (Karte :): 30
- Taste: Ausgabe
- currentValue: nil

Es sagt uns alles, was wir brauchen, um schnell herauszufinden, wo das Problem liegt. Ich habe festgestellt, dass bei Verwendung der AlamofireObjectMapper-Integration die Fehler unterdrückt werden, was alles andere als ideal ist.

Codierbar

Die entsprechende Implementierung von Codable ist wie folgt

Es ist sehr ähnlich zu ObjectMapper, obwohl die Schlüssel mithilfe des CodingKey-Protokolls als Aufzählungen definiert sind.

Es gibt eine wirklich nette Funktion, die Codable verwendet, da der Initialisierer für Sie generiert werden kann, wenn die Aufzählungsfälle der Eigenschaft entsprechen und der Typ, dem wir zuordnen, selbst decodierbar ist. Ein Beispiel dafür ist CodableConfig oben. Da alle Eigenschaften selbst decodierbar sind, müssen wir keinen Initialisierer schreiben!

Validierung

Dies funktioniert genauso wie ObjectMapper

Der Initialisierer gibt einen Fehler aus, wenn eine Fehlerzuordnung vorliegt, die an der anrufenden Site behandelt werden kann. Verwenden Sie auch hier die Optionals, um zu entscheiden, wie Fehler am besten behandelt werden.

Benutzerdefinierte Transformation

Sie werden feststellen, dass im obigen Code alles etwas unklar wird, wenn wir versuchen, unseren NSRegularExpression-Typ zuzuordnen. Wir müssen plötzlich den Initialisierer init (vom Decoder: Decoder) implementieren und uns einen KeyedDecodingContainer vom Decoder holen

Es gibt bereits eine großartige Zusammenfassung darüber, wenn Sie mehr Details wünschen, auf die ich hier nicht näher eingehen werde.

Der Code wird jetzt ziemlich ausführlich und wir wiederholen den Transformationscode. Dies ist in diesem Fall nur eine zusätzliche Zeile. Es gibt jedoch häufig Situationen, in denen ich komplexere Transformationen schreiben möchte, die ich wie mit ObjectMapper isolieren möchte

Daher habe ich eine kleine Bibliothek erstellt, um die Unterstützung für benutzerdefinierte Transformationen hinzuzufügen. Dies ist über CocoaPods verfügbar, oder Sie können die Quelle einfach kopieren, da es sich nur um ein paar Dateien handelt.

Möglicherweise möchten Sie dem Typ, den Sie nicht besitzen, eine Erweiterung hinzufügen, aber es gibt eine gute Erklärung, warum dies in Swift Evolution nicht möglich ist.

Mit der CodableExtensions-Bibliothek können wir unseren Code jetzt so vereinfachen, dass er ObjectMapper sehr ähnlich ist

Und der RegexCodableTransformer ähnelt dem, was wir zuvor mit ObjectMapper hatten

Die Bibliothek vereinfacht auch die Schnittstelle zu container.decode (), sodass der Typ nicht mehr übergeben werden muss, wenn er abgeleitet wird.

Fehlerbehandlung

Ich verwende dieselbe JSON-Datei, um die Fehlerbehandlung wie zuvor zu vergleichen. Der Fehler sieht aus wie

keyNotFound (config_spike.CodableRewriter. (CodingKeys in _4D474241C6D85B5C48988D77CA644850) .output, Swift.DecodingError.Context (codingPath: [config_spike.CodableConfig. ").", zugrunde liegender Fehler: nil))

Der Fehler sieht nicht ganz so hübsch aus, aber er hat alles, um das Problem zu beheben.

Fazit

Es gibt weit mehr Gemeinsamkeiten als Unterschiede zwischen den beiden Ansätzen. Wenn Transformationen wichtig sind, funktioniert ObjectMapper sofort. Einer der Hauptgründe für den Wechsel ist jedoch die Umstellung auf den von Apple entwickelten Standard, ohne dass eine andere Bibliothek hinzugefügt werden muss.

Wenn Transformationen wichtig sind, können Sie mit Codable dasselbe Verhalten erzielen, indem Sie einige Protokolle hinzufügen

Wir haben uns entschlossen, jetzt auf Codable umzusteigen, da alle neuen Funktionen in Zukunft verfügbar sind. Ich bin mir sicher, dass ich einige Features von dieser Liste verpasst habe, aber ich habe die wichtigsten für uns ausgewählt.