将JSON / NSDictionary反序列化为Swift对象

有没有一种方法正确反序列化的Swift对象响应的JSON响应。 使用DTO作为固定JSON API的容器?

类似于http://james.newtonking.com/json或类似于Java的这个例子

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

由此jsonResponse.toString()是类似的

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

SWIFT 4更新


既然你给了一个非常简单的JSON对象,准备处理这个模型的代码。 如果您需要更复杂的JSON模型,则需要改进此示例。

您的自定义对象

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

这就是你如何用JSONstring调用你的自定义类。

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

Swift 2 :我真的很喜欢Mohacs以前的post! 为了使它更加面向对象,我写了一个匹配的扩展:

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

自定义类:

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

使用JSONstring调用自定义类:

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

我build议你使用代码生成( http://www.json4swift.com )从json响应中创build原生模型,这样可以节省你手工分析的时间,并减less由于错误的键而导致错误的风险,所有元素将被模型属性访问,这将是纯粹的本地和模型将更有意义,而不是检查的关键。

您的转换将如下简单:

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

还有另一个我写的JSON处理程序:

有了它,你可以这样走:

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

你看不到!? 下标之间需要。

除此之外,您可以像这样应用自己的模式:

 //// 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 string:String? { return self["string"].asString } var url: String? { return self["url"].asString } 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.string // String? myjson.url // String? 

我最近编写了这个小型的开源库,可以让你快速轻松地将字典反序列化为Swift对象: https : //github.com/isair/JSONHelper

使用它,反序列化数据变得如此简单:

 var myInstance = MyClass(data: jsonDictionary) 

要么

 myInstance <-- jsonDictionary 

模型只需要看起来像这样:

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

在你的情况下,这将是:

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

如果你想从jsonparsing而不需要手动映射键和字段,那么你也可以使用EVReflection 。 然后你可以使用如下代码:

 var user:User = User(json:jsonString) 

要么

 var jsonString:String = user.toJsonString() 

你唯一需要做的就是使用EVObject作为数据对象的基类。 有关更详细的示例代码,请参阅GitHub页面

苹果用Swift 2.0反序列化JSON是一个很好的例子

诀窍是使用guard关键字并链接分配,如下所示:

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

我个人比任何第三方都更喜欢本地parsing,因为它是透明和无魔力的。 (和bug更less?)

HandyJSON是为您处理JSON的另一种select。 https://github.com/alibaba/handyjson

它释放JSON直接反对。 不需要指定映射关系,不需要从NSObjectinheritance。 只需定义你的纯粹的快速类/结构,并对其进行反序列化JSON即可。

类动物:HandyJSON {
     var name:String?
     var id:String?
     var num:Int?

    需要init(){}
 }

让jsonString =“{\”name \“:\”cat \“,\”id \“:\”12345 \“,\”num \“:180}

如果让动物= JSONDeserializer.deserializeFrom(jsonString){
    打印(动物)
 }

我正在扩展Mohacs和Peter Kreinz的优秀答案,以便涵盖类似对象的情况,其中每个对象都包含有效的JSON数据types的混合。 如果parsing的JSON数据是包含JSON数据types混合的类似对象的数组,则parsingJSON数据的do循环变成这样。

 // Array of parsed objects var parsedObjects = [ParsedObject]() do { let json = try NSJSONSerialization.JSONObjectWithData(jsonData, options: []) as [Dictionary<String, AnyObject>] // 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 String, 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(NSSelectorFromString(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)") } 

这种方式可以让你从一个URL获取用户。 它将NSDataparsing为NSDictionary,然后parsingNSObject。

 let urlS = "http://api.localhost:3000/" func getUser(username: Strung) -> User { var user = User() let url = NSURL(string: "\(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? String, let value = value as? String { if (object.respondsToSelector(NSSelectorFromString(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 } 

使用quicktype ,我从你的示例生成了你的模型和序列化助手:

 import Foundation struct User: Codable { let name: String let email: String let password: String } extension User { static func from(json: String, using encoding: String.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 jsonString: String? { guard let data = self.jsonData else { return nil } return String(data: data, encoding: .utf8) } } 

然后parsingUser值如下:

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

你通过使用NSJSONSerialization来做到这一点数据是你的JSON。

首先将它封装在if语句中以提供一些error handlingfunction

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

然后分配他们:

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

现在,这会告诉你结果:

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

采取从这个SwiftparsingJSON教程。 你应该看看教程,因为它深入了很多,涵盖了更好的error handling。