Codable vs ObjectMapper

Photo par https://unsplash.com/photos/_rNVw54xZZg

J’ai récemment expérimenté le nouveau protocole Codable de Swift afin de mapper le code JSON extrait d’un service distant dans un objet modèle Swift.

Pour un peu d’arrière-plan, Codable a été ajouté à Swift 4 afin de permettre aux objets de se convertir eux-mêmes en une représentation externe. Codable lui-même est juste un typealias de Decodable et Encodable.

Pour ce billet, je vais me concentrer sur la partie décodable, car c’est la conversion d’une représentation JSON distante qui m’intéresse.

Comparaison

J’ai beaucoup utilisé ObjectMapper dans le passé, mais comme Codable est maintenant intégré à Swift, je voulais faire une comparaison entre les deux. Les fonctionnalités que je souhaite comparer sont les suivantes:

  • Validation
  • Transformation personnalisée (mappage dans des types personnalisés, par exemple une carte JSON dans une expression régulière)
  • Erreur de traitement

Les données que je vais analyser sont la configuration réelle que nous récupérons à distance pour l’application BBC Sport.

C’est une structure JSON assez simple, mais elle contient quelques expressions régulières dans lesquelles je voudrais mapper vers NSRegularExpression, pas une chaîne.

ObjectMapper

Les structures requises pour mapper ce modèle JSON avec ObjectMapper sont les suivantes.

Les stucts sont tous conformes au protocole ImmutableMappable, ce qui signifie qu'ils ont besoin d'un constructeur prenant un objet Map et lançant une erreur en cas d'échec du mappage.

Validation

Pour effectuer la validation, vous pouvez utiliser Optionals. Dans cet exemple, nous avons décidé que l'application pouvait fonctionner sans ces adresses e-mail. Les e-mails sont donc facultatifs. map.values ​​("emails") renvoie une erreur si la clé n’est pas présente ou si le type ne peut pas être converti. Nous faisons usage d'essayer? capturer cette erreur et la transformer en une valeur nulle en cas d'erreur.

Si nous décidons qu'une propriété particulière est requise, nous ne la marquons pas comme étant facultative et ne permettons pas à l'erreur de se propager.

Globalement, la validation est très simple avec ImmutableMappable

Vous avez peut-être remarqué qu’un argument supplémentaire avait été passé dans cet appel map.value («regex», en utilisant: RegexTransformer ()). C’est pour la transformation personnalisée de transformer la chaîne en NSRegularExpression, ce qui me permet d’atteindre mon point suivant!

Transformation personnalisée

ObjectMapper prend en charge les transformations personnalisées prêtes à l'emploi et il est très simple.

Nous n’implémentons ici que le protocole TransformType et la méthode transformFromJSON associée. Cela prend dans un type et que nous lançons dans String puis essayons en toute sécurité? convertir la chaîne en NSRegularExpression.

Ce transformateur est alors disponible pour être réutilisé n'importe où

La gestion des erreurs

Pour tester le traitement des erreurs, je vais utiliser un fichier JSON avec la clé de sortie manquante.

Lorsque vous exécutez ceci via ObjectMapper, nous obtenons un message d'erreur utile et utile.

Vous avez une erreur lors de la cartographie.
- raison: impossible de convertir en 'Chaîne'
- emplacement: Config.init (map :): 30
- clé: sortie
- currentValue: nil

Il nous dit tout ce dont nous avons besoin pour trouver rapidement où est le problème. J'ai constaté lors de l'utilisation de l'intégration AlamofireObjectMapper que les erreurs sont supprimées, ce qui est loin d'être idéal.

Codable

L'implémentation équivalente de Codable est la suivante:

Il est très similaire à ObjectMapper bien que les clés soient définies comme des énumérations utilisant le protocole CodingKey.

C’est une fonctionnalité très intéressante qui utilise Codable en ce sens que l’initialiseur peut être généré pour vous si les cas enum sont égaux à la propriété, et que le type que nous mappons est lui-même Decodable Un exemple de cela est CodableConfig ci-dessus. Puisque toutes ses propriétés sont elles-mêmes décodables, nous n’avons pas besoin d’écrire un initialiseur!

Validation

Cela fonctionne exactement comme ObjectMapper

L’initialiseur renvoie une erreur s’il existe un mappage d’erreur pouvant être traité sur le site de l’appel. Encore une fois, faites bon usage de Optionals ici pour décider de la meilleure façon de gérer les erreurs.

Transformation personnalisée

Vous remarquerez que, dans le code ci-dessus, tout devient un peu moins clair lorsque nous essayons de mapper vers notre type NSRegularExpression. Nous devons soudainement implémenter l'initializer init (à partir de decoder: Decoder) et obtenir nous-mêmes un KeyedDecodingContainer à partir du Decoder

Si vous souhaitez plus de détails, il existe déjà un excellent article sur ce sujet, que je ne vais pas aborder ici.

Le code devient assez détaillé à écrire maintenant, et nous répétons le code de transformation. Dans ce cas, il ne s’agit là que d’une ligne supplémentaire, mais j’ai souvent envie d’écrire des transformations plus complexes que je voudrais isoler comme je le pouvais avec ObjectMapper.

J'ai donc créé une petite bibliothèque pour ajouter la prise en charge des transformations personnalisées disponible via CocoaPods, ou vous pouvez simplement copier le code source car il ne s'agit que de deux fichiers.

Vous pourriez penser à ajouter une extension au type que vous ne possédez pas, mais il existe une bonne explication de la raison pour laquelle cela n’est pas possible sur Swift Evolution.

En utilisant la bibliothèque CodableExtensions, nous pouvons maintenant simplifier notre code pour qu’il ressemble beaucoup à ObjectMapper.

Et RegexCodableTransformer est également très similaire à ce que nous avions précédemment avec ObjectMapper

La bibliothèque simplifie également l’interface avec container.decode (), il n’est donc plus nécessaire de transmettre le type tel qu’il est déduit.

La gestion des erreurs

J'utilise le même fichier JSON pour comparer le traitement des erreurs comme auparavant. L'erreur ressemble à

Couchez-vousS (Cf.CodableReporte. (Cf.CodableReporte (bricolage)) ").", sous-jacenteError: nil))

L’erreur n’est pas aussi jolie, mais elle a tout pour déboguer le problème.

Conclusion

Il y a beaucoup plus de similitudes que de différences entre les deux approches. Si les transformations sont importantes, ObjectMapper fonctionne immédiatement. Cependant, l’un des principaux facteurs de motivation du changement est le passage à la norme créée par Apple sans avoir à importer une autre bibliothèque.

Si les transformations sont importantes, en ajoutant quelques protocoles, vous pouvez obtenir le même comportement avec Codable.

Nous avons décidé de passer à Codable pour toutes nos nouvelles fonctionnalités. Je suis sûr que certaines fonctionnalités me manquent, mais j’ai choisi les plus importantes pour nous.