web-dev-qa-db-fra.com

Sérialisation et désérialisation JSON automatiques des objets dans Swift

Je cherche un moyen de sérialiser et désérialiser automatiquement les instances de classe dans Swift. Supposons que nous avons défini la classe suivante…

class Person {
    let firstName: String
    let lastName: String

    init(firstName: String, lastName: String) {
        self.firstName = firstName
        self.lastName = lastName
    }
}

… Et Person instance:

let person = Person(firstName: "John", lastName: "Doe")

La représentation JSON de person serait la suivante:

{
    "firstName": "John",
    "lastName": "Doe"
}

Maintenant, voici mes questions:

  1. Comment puis-je sérialiser l'instance person et obtenir le JSON ci-dessus sans avoir à ajouter manuellement toutes les propriétés de la classe à un dictionnaire qui est transformé en JSON?
  2. Comment désérialiser le JSON ci-dessus et récupérer un objet instancié qui est statiquement typé pour être de type Person? Encore une fois, je ne veux pas mapper les propriétés manuellement.

Voici comment procéder en C # en utilisant Json.NET :

var person = new Person("John", "Doe");
string json = JsonConvert.SerializeObject(person);
// {"firstName":"John","lastName":"Doe"}

Person deserializedPerson = JsonConvert.DeserializeObject<Person>(json);
38
Marius Schulz

Comme indiqué dans WWDC2017 @ 24:48 ( Swift 4 ), nous pourrons utiliser le protocole Codable. Exemple

public struct Person : Codable {
   public let firstName:String
   public let lastName:String
   public let location:Location
}

Pour sérialiser

let payload: Data = try JSONEncoder().encode(person)

Désérialiser

let anotherPerson = try JSONDecoder().decode(Person.self, from: payload)

Notez que toutes les propriétés doivent être conformes au protocole codable.

Une alternative peut être JSONCodable qui est utilisée par Swagger's générateur de code.

26
Alex Nolasco

Vous pouvez utiliser EVReflection pour cela. Vous pouvez utiliser du code comme:

var person:Person = Person(json:jsonString)

ou

var jsonString:String = person.toJsonString()

Voir la page GitHub pour un exemple de code plus détaillé. Vous n'avez qu'à faire d'EVObject la classe de base de vos objets de données. Aucun mappage n'est nécessaire (tant que les clés json sont identiques aux noms de propriété)

Mise à jour: Swift 4 prend en charge Codable, ce qui le rend presque aussi simple que EVReflection mais avec de meilleures performances. Si vous voulez utiliser un entrepreneur simple comme ci-dessus, alors vous pouvez utiliser cette extension: Stuff/Codable

20
Edwin Vermeer

Avec Swift 4, vous devez simplement rendre votre classe conforme aux protocoles Codable (Encodable et Decodable) afin de pouvoir effectuer la sérialisation et la désérialisation JSON.

import Foundation

class Person: Codable {
    let firstName: String
    let lastName: String

    init(firstName: String, lastName: String) {
        self.firstName = firstName
        self.lastName = lastName
    }
}

sage # 1 (encoder une instance Person dans une chaîne JSON):

let person = Person(firstName: "John", lastName: "Doe")
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted // if necessary
let data = try! encoder.encode(person)
let jsonString = String(data: data, encoding: .utf8)!
print(jsonString)

/*
 prints:
 {
   "firstName" : "John",
   "lastName" : "Doe"
 }
 */

sage # 2 (décoder une chaîne JSON en une instance Person):

let jsonString = """
{
  "firstName" : "John",
  "lastName" : "Doe"
}
"""

let jsonData = jsonString.data(using: .utf8)!
let decoder = JSONDecoder()
let person = try! decoder.decode(Person.self, from: jsonData)
dump(person)

/*
 prints:
 ▿ __lldb_expr_609.Person #0
   - firstName: "John"
   - lastName: "Doe"
 */
8
Imanou Petit

Il existe une classe Foundation appelée NSJSONSerialization qui peut effectuer la conversion vers et depuis JSON.

La méthode de conversion de JSON en objet ressemble à ceci:

let jsonObject = NSJSONSerialization.JSONObjectWithData(data, 
    options: NSJSONReadingOptions.MutableContainers, 
    error: &error) as NSDictionary

Notez que le premier argument de cette méthode est les données JSON, mais pas en tant qu'objet chaîne, mais plutôt en tant qu'objet NSData (c'est ainsi que vous obtiendrez souvent des données JSON de toute façon).

Vous souhaiterez très probablement une méthode d'usine pour votre classe qui prend les données JSON comme argument, utilise cette méthode et retourne un objet initialize de votre classe.

Pour inverser ce processus et créer des données JSON à partir d'un objet, vous voudrez utiliser dataWithJSONObject, dans lequel vous passerez un objet qui peut être converti en JSON et avoir un NSData? revenu. Encore une fois, vous souhaiterez probablement créer une méthode d'assistance qui ne nécessite aucun argument comme méthode d'instance de votre classe.


Pour autant que je sache, la façon la plus simple de gérer cela est de créer un moyen de mapper les propriétés de vos objets dans un dictionnaire et de passer ce dictionnaire pour transformer votre objet en données JSON. Ensuite, lorsque vous transformez vos données JSON en objet, attendez-vous à ce qu'un dictionnaire soit renvoyé et inversez le processus de mappage. Il y a peut-être un moyen plus simple.

5
nhgrif

Vous pouvez y parvenir en utilisant la bibliothèque ObjectMapper . Cela vous donnera plus de contrôle sur les noms de variables et les valeurs et le JSON préparé. Après avoir ajouté cette bibliothèque, étendez la classe Mappable et définissez la fonction mapping(map: Map).

Par exemple

   class User: Mappable {
       var id: Int?
       var name: String?

       required init?(_ map: Map) {

       }

       // Mapping code
       func mapping(map: Map) {
          name    <- map["name"]
          id      <- map["id"]
       }

    }

Utilisez-le comme ci-dessous

   let user = Mapper<User>().map(JSONString)
4
Penkey Suresh

Tout d'abord, créez un objet Swift comme celui-ci

struct Person {
    var firstName: String?;
    var lastName: String?;
    init() {

    }
}

Après cela, sérialisez vos données JSON que vous avez récupérées, en utilisant la fonction intégrée NSJSONSerialization et analysez les valeurs dans le Personne objet.

var person = Person();
var error: NSError?;
var response: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(), error: &error);

if let personDictionary = response as? NSDictionary {
    person.firstName = personDictionary["firstName"] as? String;
    person.lastName = personDictionary["lastName"] as? String;
}

MISE À JOUR:

Jetez également un œil à ces bibliothèques

Swift-JsonSerialiser

ROJSONParser

0
Eddy Liu

Jetez un œil à NSKeyValueCoding.h, en particulier setValuesForKeysWithDictionary. Une fois que vous avez désérialisé le json en un NSDictionary, vous pouvez ensuite créer et initialiser votre objet avec cette instance de dictionnaire, pas besoin de définir manuellement des valeurs sur l'objet. Cela vous donnera une idée de la façon dont la désérialisation pourrait fonctionner avec json, mais vous découvrirez bientôt que vous avez besoin de plus de contrôle sur le processus de désérialisation. C'est pourquoi j'implémente une catégorie sur NSObject qui permet une initialisation NSObject entièrement contrôlée avec un dictionnaire pendant la désérialisation json, elle enrichit essentiellement l'objet encore plus que ce que setValuesForKeysWithDictionary peut faire. J'ai également un protocole utilisé par le désérialiseur json, qui permet à l'objet en cours de désérialisation de contrôler certains aspects, par exemple, si la désérialisation d'un NSArray d'objets, il demandera à cet objet quel est le nom de type des objets stockés dans le tableau.

0
simplatek