Désérialiser les objects JSON / NSDictionary en objects rapides

Existe-t-il un moyen de désérialiser correctement une réponse JSON aux objects Swift resp. utiliser les DTO comme conteneurs pour les API JSON fixes?

Quelque chose de similaire à http://james.newtonking.com/json ou quelque chose comme cet exemple de Java

User user = jsonResponse.readEntity(User.class); 

jsonResponse.toSsortingng() est quelque chose comme

 { "name": "myUser", "email": "user@example.com", "password": "passwordHash" } 

Mise à jour SWIFT 4


Puisque vous donnez un object JSON très simple, le code préparé pour gérer ce modèle. Si vous avez besoin de modèles JSON plus compliqués, vous devez améliorer cet exemple.

Votre object personnalisé

 class Person : NSObject { var name : Ssortingng = "" var email : Ssortingng = "" var password : Ssortingng = "" init(JSONSsortingng: Ssortingng) { super.init() var error : NSError? let JSONData = JSONSsortingng.dataUsingEncoding(NSUTF8SsortingngEncoding, allowLossyConversion: false) let JSONDictionary: Dictionary = NSJSONSerialization.JSONObjectWithData(JSONData, options: nil, error: &error) as NSDictionary // Loop for (key, value) in JSONDictionary { let keyName = key as Ssortingng let keyValue: Ssortingng = value as Ssortingng // If property exists if (self.respondsToSelector(NSSelectorFromSsortingng(keyName))) { self.setValue(keyValue, forKey: keyName) } } // Or you can do it with using // self.setValuesForKeysWithDictionary(JSONDictionary) // instead of loop method above } } 

Et c’est ainsi que vous appelez votre classe personnalisée avec une chaîne JSON.

 override func viewDidLoad() { super.viewDidLoad() let jsonSsortingng = "{ \"name\":\"myUser\", \"email\":\"user@example.com\", \"password\":\"passwordHash\" }" var aPerson : Person = Person(JSONSsortingng: jsonSsortingng) println(aPerson.name) // Output is "myUser" } 

Swift 2 : J’aime beaucoup le post précédent de Mohacs! Pour le rendre plus orienté object, j’ai écrit une extension correspondante:

 extension NSObject{ convenience init(jsonStr:Ssortingng) { self.init() if let jsonData = jsonStr.dataUsingEncoding(NSUTF8SsortingngEncoding, allowLossyConversion: false) { do { let json = try NSJSONSerialization.JSONObjectWithData(jsonData, options: []) as! [Ssortingng: AnyObject] // Loop for (key, value) in json { let keyName = key as Ssortingng let keyValue: Ssortingng = value as! Ssortingng // If property exists if (self.respondsToSelector(NSSelectorFromSsortingng(keyName))) { self.setValue(keyValue, forKey: keyName) } } } catch let error as NSError { print("Failed to load: \(error.localizedDescription)") } } else { print("json is of wrong format!") } } } 

classes personnalisées:

 class Person : NSObject { var name : Ssortingng? var email : Ssortingng? var password : Ssortingng? } class Address : NSObject { var city : Ssortingng? var zip : Ssortingng? } 

invocation de classes personnalisées avec une chaîne JSON:

 var jsonSsortingng = "{ \"name\":\"myUser\", \"email\":\"user@example.com\", \"password\":\"passwordHash\" }" let aPerson = Person(jsonStr: jsonSsortingng) print(aPerson.name!) // Output is "myUser" jsonSsortingng = "{ \"city\":\"Berlin\", \"zip\":\"12345\" }" let aAddress = Address(jsonStr: jsonSsortingng) print(aAddress.city!) // Output is "Berlin" 

Je vous recommande d’utiliser la génération de code ( http://www.json4swift.com ) pour créer des modèles natifs à partir de la réponse json, cela économisera votre temps d’parsing manuelle et réduira le risque d’erreurs dues à des clés erronées, à tous les éléments. sera accessible par les propriétés du modèle, ce sera purement natif et les modèles auront plus de sens plutôt que de vérifier les clés.

Votre conversion sera aussi simple que:

 let userObject = UserClass(userDictionary) print(userObject!.name) 

J’ai encore écrit un autre gestionnaire JSON:

Avec cela, vous pouvez aller comme ceci:

 let obj:[Ssortingng:AnyObject] = [ "array": [JSON.null, false, 0, "", [], [:]], "object":[ "null": JSON.null, "bool": true, "int": 42, "double": 3.141592653589793, "ssortingng": "a α\t弾\n𪚲", "array": [], "object": [:] ], "url":"http://blog.livedoor.com/dankogai/" ] let json = JSON(obj) json.toSsortingng() json["object"]["null"].asNull // NSNull() json["object"]["bool"].asBool // true json["object"]["int"].asInt // 42 json["object"]["double"].asDouble // 3.141592653589793 json["object"]["ssortingng"].asSsortingng // "a α\t弾\n𪚲" json["array"][0].asNull // NSNull() json["array"][1].asBool // false json["array"][2].asInt // 0 json["array"][3].asSsortingng // "" 

Comme tu vois non !? nécessaire entre les indices.

En plus de cela, vous pouvez appliquer votre propre schéma comme ceci:

 //// schema by subclassing class MyJSON : JSON { override init(_ obj:AnyObject){ super.init(obj) } override init(_ json:JSON) { super.init(json) } var null :NSNull? { return self["null"].asNull } var bool :Bool? { return self["bool"].asBool } var int :Int? { return self["int"].asInt } var double:Double? { return self["double"].asDouble } var ssortingng:Ssortingng? { return self["ssortingng"].asSsortingng } var url: Ssortingng? { return self["url"].asSsortingng } var array :MyJSON { return MyJSON(self["array"]) } var object:MyJSON { return MyJSON(self["object"]) } } let myjson = MyJSON(obj) myjson.object.null // NSNull? myjson.object.bool // Bool? myjson.object.int // Int? myjson.object.double // Double? myjson.object.ssortingng // Ssortingng? myjson.url // Ssortingng? 

Il y a un excellent exemple d’Apple pour la désérialisation de JSON avec Swift 2.0

L’astuce consiste à utiliser le mot-clé guard et à enchaîner les affectations comme suit:

 init?(atsortingbutes: [Ssortingng : AnyObject]) { guard let name = atsortingbutes["name"] as? Ssortingng, let coordinates = atsortingbutes["coordinates"] as? [Ssortingng: Double], let latitude = coordinates["lat"], let longitude = coordinates["lng"], else { return nil } self.name = name self.coordinates = CLLocationCoordinate2D(latitude: latitude, longitude: longitude) } 

Personnellement, je préfère l’parsing syntaxique native à n’importe quelle tierce partie, car elle est transparente et sans magie. (et bug moins?)

J’ai récemment écrit cette petite bibliothèque open source qui vous permet de désérialiser rapidement et facilement des dictionnaires en objects Swift: https://github.com/isair/JSONHelper

En l’utilisant, la désérialisation des données devient aussi simple que cela:

 var myInstance = MyClass(data: jsonDictionary) 

ou

 myInstance <-- jsonDictionary 

Et les modèles doivent ressembler à ceci:

 struct SomeObjectType: Deserializable { var someProperty: Int? var someOtherProperty: AnotherObjectType? var yetAnotherProperty: [YetAnotherObjectType]? init(data: [Ssortingng: AnyObject]) { someProperty <-- data["some_key"] someOtherProperty <-- data["some_other_key"] yetAnotherProperty <-- data["yet_another_key"] } } 

Lequel, dans votre cas, serait:

 struct Person: Deserializable { var name: Ssortingng? var email: Ssortingng? var password: Ssortingng? init(data: [Ssortingng: AnyObject]) { name <-- data["name"] email <-- data["email"] password <-- data["password"] } } 

Si vous souhaitez parsingr depuis et vers json sans avoir à mapper manuellement les clés et les champs, vous pouvez également utiliser EVReflection . Vous pouvez ensuite utiliser un code comme:

 var user:User = User(json:jsonSsortingng) 

ou

 var jsonSsortingng:Ssortingng = user.toJsonSsortingng() 

La seule chose à faire est d’utiliser EVObject comme classe de base des objects de données. Voir la page GitHub pour un exemple de code plus détaillé

HandyJSON est une autre option pour gérer JSON pour vous. https://github.com/alibaba/handyjson

Il désérial JSON pour objecter directement. Pas besoin de spécifier une relation de mappage, pas besoin d’hériter de NSObject. Il suffit de définir votre classe / struct pure-swift, et son JSON deserial.

 classe Animal: HandyJSON {
     var nom: Ssortingng?
     var id: Ssortingng?
     var num: Int?

     requirejs init () {}
 }

 let jsonSsortingng = "{\" name \ ": \" cat \ ", \" id \ ": \" 12345 \ ", \" num \ ": 180}"

 si let animal = JSONDeserializer.deserializeFrom (jsonSsortingng) {
     imprimer (animal)
 }

Je développe un peu les excellentes réponses de Mohacs et Peter Kreinz pour couvrir le tableau de cas similaires où chaque object contient un mélange de types de données JSON valides. Si les données JSON analysées sont un tableau d’objects similaires contenant un mélange de types de données JSON, la boucle do permettant d’parsingr les données JSON devient ceci.

 // Array of parsed objects var parsedObjects = [ParsedObject]() do { let json = try NSJSONSerialization.JSONObjectWithData(jsonData, options: []) as [Dictionary] // Loop through objects for dict in json { // ParsedObject is a single instance of an object inside the JSON data // Its properties are a mixture of Ssortingng, Int, Double and Bool let parsedObject = ParsedObject() // Loop through key/values in object parsed from JSON for (key, value) in json { // If property exists, set the value if (parsedObject.respondsToSelector(NSSelectorFromSsortingng(keyName))) { // setValue can handle AnyObject when assigning property value parsedObject.setValue(keyValue, forKey: keyName) } } parsedObjects.append(parsedObject) } } catch let error as NSError { print("Failed to load: \(error.localizedDescription)") } 

En utilisant quicktype , j’ai généré vos assistants de modèle et de sérialisation à partir de votre exemple:

 import Foundation struct User: Codable { let name: Ssortingng let email: Ssortingng let password: Ssortingng } extension User { static func from(json: Ssortingng, using encoding: Ssortingng.Encoding = .utf8) -> OtherUser? { guard let data = json.data(using: encoding) else { return nil } return OtherUser.from(data: data) } static func from(data: Data) -> OtherUser? { let decoder = JSONDecoder() return try? decoder.decode(OtherUser.self, from: data) } var jsonData: Data? { let encoder = JSONEncoder() return try? encoder.encode(self) } var jsonSsortingng: Ssortingng? { guard let data = self.jsonData else { return nil } return Ssortingng(data: data, encoding: .utf8) } } 

Ensuite, parsingz User valeurs User comme ceci:

 let user = User.from(json: """{ "name": "myUser", "email": "user@example.com", "password": "passwordHash" }""")! 

Dans Swift 4, vous pouvez utiliser les protocoles Decoding , CodingKey pour désérialiser la réponse JSON:

  1. Créer la classe qui confirme le protocole décodable

    class UserInfo: Decodable

  2. Créer des membres de la classe

    var name: Ssortingng

    var email: Ssortingng

    var password: Ssortingng

  3. Créer une clé JSON enum qui hérite de CodingKey

    enum UserInfoCodingKey: Ssortingng, CodingKey { case name case password case emailId }

  4. Implémenter init

    required init(from decoder: Decoder) throws

    La classe entière ressemble à:

    entrer la description de l'image ici

  5. Décodeur d’appel

    // jsonData est une réponse JSON et nous obtenons l’object userInfo

    let userInfo = try JsonDecoder().decode(UserInfo.self, from: jsonData)

De cette façon, vous pouvez obtenir l’utilisateur d’une URL. Il parsing les NSData vers un NSDictionary, puis vers votre NSObject.

 let urlS = "http://api.localhost:3000/" func getUser(username: Strung) -> User { var user = User() let url = NSURL(ssortingng: "\(urlS)\(username)") if let data = NSData(contentsOfURL: url!) { setKeysAndValues(user, dictionary: parseData(data)) } return user } func setKeysAndValues (object : AnyObject, dictionary : NSDictionary) -> AnyObject { for (key, value) in dictionary { if let key = key as? Ssortingng, let value = value as? Ssortingng { if (object.respondsToSelector(NSSelectorFromSsortingng(key))) { object.setValue(value, forKey: key) } } } return object } func parseData (data : NSData) -> NSDictionary { var error: NSError? return NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &error) as! NSDictionary } 

Vous faites cela en utilisant NSJSONSerialization . Où les données sont votre JSON.

D’abord, enveloppez-le dans une instruction if pour fournir une capacité de traitement des erreurs.

 if let data = data, json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? [Ssortingng: AnyObject] { // Do stuff } else { // Do stuff print("No Data :/") } 

puis assignez-les:

 let email = json["email"] as? Ssortingng let name = json["name"] as? Ssortingng let password = json["password"] as? Ssortingng 

Maintenant, cela vous montrera le résultat:

 print("Found User iname: \(name) with email: \(email) and pass \(password)") 

Tiré de ce tutoriel Swift Parse JSON . Vous devriez vérifier le tutoriel car il va beaucoup plus en profondeur et couvre une meilleure gestion des erreurs.