将 JSON / NSDictionary 反序列化为 Swift 对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24310324/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Deserialize JSON / NSDictionary to Swift objects
提问by dimitri
Is there a way to properly deserialize a JSON response to Swift objects resp. using DTOs as containers for fixed JSON APIs?
有没有办法正确反序列化对 Swift 对象的 JSON 响应。使用 DTO 作为固定 JSON API 的容器?
Something similar to http://james.newtonking.com/jsonor something like this example from Java
类似于http://james.newtonking.com/json或类似 Java 示例的内容
User user = jsonResponse.readEntity(User.class);
whereby jsonResponse.toString()is something like
其中jsonResponse.toString()是这样的
{
"name": "myUser",
"email": "[email protected]",
"password": "passwordHash"
}
回答by mohacs
Since you give a very simple JSON object the code prepared for to handle that model. If you need more complicated JSON models you need to improve this sample.
由于您提供了一个非常简单的 JSON 对象,因此准备好处理该模型的代码。如果您需要更复杂的 JSON 模型,则需要改进此示例。
Your Custom Object
您的自定义对象
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
}
}
And this is how you invoke your custom class with JSON string.
这就是您使用 JSON 字符串调用自定义类的方式。
override func viewDidLoad() {
super.viewDidLoad()
let jsonString = "{ \"name\":\"myUser\", \"email\":\"[email protected]\", \"password\":\"passwordHash\" }"
var aPerson : Person = Person(JSONString: jsonString)
println(aPerson.name) // Output is "myUser"
}
回答by Syed Absar
I recommend that you use code generation (http://www.json4swift.com) to create native models out of the json response, this will save your time of parsing by hand and reduce the risk of errors due to mistaken keys, all elements will be accessible by model properties, this will be purely native and the models will make more sense rather checking the keys.
我建议您使用代码生成(http://www.json4swift.com)从 json 响应中创建原生模型,这将节省您手动解析的时间并降低因错误键、所有元素而导致错误的风险将可以通过模型属性访问,这将是纯原生的,模型将更有意义,而不是检查密钥。
Your conversion will be as simple as:
您的转换将非常简单:
let userObject = UserClass(userDictionary)
print(userObject!.name)
回答by Peter Kreinz
Swift 2: I really like the previous post of Mohacs! To make it more object oriented, i wrote a matching Extension:
Swift 2: 我真的很喜欢 Mohacs 的上一篇文章!为了使它更面向对象,我写了一个匹配的扩展:
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!")
}
}
}
custom classes:
自定义类:
class Person : NSObject {
var name : String?
var email : String?
var password : String?
}
class Address : NSObject {
var city : String?
var zip : String?
}
invoking custom classes with JSON string:
使用 JSON 字符串调用自定义类:
var jsonString = "{ \"name\":\"myUser\", \"email\":\"[email protected]\", \"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"
回答by dankogai
Yet another JSON handler I wrote:
我写的另一个 JSON 处理程序:
With it you can go like this:
有了它,你可以这样:
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 // ""
As you see no !?needed between subscripts.
如您所见!?,下标之间不需要。
In addition to that you can apply your own schema like this:
除此之外,您可以像这样应用自己的架构:
//// 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?
回答by AmitP
There's a great exampleby Apple for deserializing JSON with Swift 2.0
Apple有一个很好的例子,用于使用 Swift 2.0 反序列化 JSON
The trick is to use the guard keyword and chain the assignments like so:
诀窍是使用 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)
}
I personally prefer native parsing vs any 3rd party, as it is transparent and magic-less. (and bug less?)
与任何 3rd 方相比,我个人更喜欢本机解析,因为它透明且无魔法。(并减少错误?)
回答by isair
I wrote this small open-source library recently that lets you quickly and easily deserialize dictionaries into Swift objects: https://github.com/isair/JSONHelper
我最近编写了这个小型开源库,它可以让您快速轻松地将字典反序列化为 Swift 对象:https: //github.com/isair/JSONHelper
Using it, deserializing data becomes as easy as this:
使用它,反序列化数据变得如此简单:
var myInstance = MyClass(data: jsonDictionary)
or
或者
myInstance <-- jsonDictionary
And models need to look only like this:
模型只需如下所示:
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"]
}
}
Which, in your case, would be:
在你的情况下,这将是:
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"]
}
}
回答by Edwin Vermeer
If you would like parse from and to json without the need to manually map keys and fields, then you could also use EVReflection. You can then use code like:
如果您想在不需要手动映射键和字段的情况下解析 json 和解析 json,那么您也可以使用EVReflection。然后,您可以使用以下代码:
var user:User = User(json:jsonString)
or
或者
var jsonString:String = user.toJsonString()
The only thing you need to do is to use EVObject as your data objects base class. See the GitHub page for more detailed sample code
您唯一需要做的就是使用 EVObject 作为您的数据对象基类。更详细的示例代码见GitHub页面
回答by xuyecan
HandyJSONis another option to deal with JSON for you. https://github.com/alibaba/handyjson
HandyJSON是为您处理 JSON 的另一种选择。https://github.com/alibaba/handyjson
It deserials JSON to object directly. No need to specify mapping relationship, no need to inherit from NSObject. Just define your pure-swift class/struct, and deserial JSON to it.
它将 JSON 反序列化为直接对象。无需指定映射关系,无需继承自NSObject。只需定义您的纯 swift 类/结构,然后将 JSON 反序列化即可。
class Animal: HandyJSON {
var name: String?
var id: String?
var num: Int?
required init() {}
}
let jsonString = "{\"name\":\"cat\",\"id\":\"12345\",\"num\":180}"
if let animal = JSONDeserializer.deserializeFrom(jsonString) {
print(animal)
}
回答by David Siegel
Using quicktype, I generated your model and serialization helpers from your sample:
使用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)
}
}
Then parse Uservalues like this:
然后User像这样解析值:
let user = User.from(json: """{
"name": "myUser",
"email": "[email protected]",
"password": "passwordHash"
}""")!
回答by jkwuc89
I am expanding upon Mohacs and Peter Kreinz's excellent answers just a bit to cover the array of like objects case where each object contains a mixture of valid JSON data types. If the JSON data one is parsing is an array of like objects containing a mixture of JSON data types, the do loop for parsing the JSON data becomes this.
我正在扩展 Mohacs 和 Peter Kreinz 的出色答案,以涵盖类似对象数组的情况,其中每个对象都包含有效 JSON 数据类型的混合。如果解析的 JSON 数据是包含 JSON 数据类型混合的相似对象数组,则解析 JSON 数据的 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)")
}

