有没有办法正确反序列化对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"
}
答案 0 :(得分:58)
因为您为一个非常简单的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
}
}
这就是您使用JSON字符串调用自定义类的方法。
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"
}
答案 1 :(得分:11)
我建议您使用代码生成(http://www.json4swift.com)从json响应中创建本机模型,这将节省您手动解析的时间并降低因错误键导致错误的风险,所有元素都将可以通过模型属性访问,这将是纯粹原生的,模型将更有意义,而不是检查键。
您的转化将非常简单:
let userObject = UserClass(userDictionary)
print(userObject!.name)
答案 2 :(得分:9)
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!")
}
}
}
自定义类:
class Person : NSObject {
var name : String?
var email : String?
var password : String?
}
class Address : NSObject {
var city : String?
var zip : String?
}
使用JSON字符串调用自定义类:
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"
答案 3 :(得分:7)
我写的另一个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?
答案 4 :(得分:4)
Apple有great example用于使用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)
}
我个人更喜欢原生解析与任何第三方,因为它透明且无魔法。 (并减少错误?)
答案 5 :(得分:3)
我最近编写了这个小型开源库,可以让您快速轻松地将字典反序列化为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"]
}
}
答案 6 :(得分:3)
如果您想要从json解析并且不需要手动映射键和字段,那么您也可以使用EVReflection。然后,您可以使用以下代码:
var user:User = User(json:jsonString)
或
var jsonString:String = user.toJsonString()
您唯一需要做的就是使用EVObject作为数据对象基类。 有关更详细的示例代码,请参阅GitHub页面
答案 7 :(得分:3)
HandyJSON
是另一种为您处理JSON的选项。 https://github.com/alibaba/handyjson
将JSON直接解析为对象。无需指定映射关系,无需从NSObject继承。只需定义你的pure-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) }
答案 8 :(得分:3)
使用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)
}
}
然后解析User
这样的值:
let user = User.from(json: """{
"name": "myUser",
"email": "user@example.com",
"password": "passwordHash"
}""")!
答案 9 :(得分:2)
我正在扩展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)")
}
答案 10 :(得分:2)
在Swift 4中,您可以使用解码, CodingKey协议来反序列化JSON响应:
创建确认可解码协议的类
class UserInfo: Decodable
创建班级成员
var name: String
var email: String
var password: String
创建继承自CodingKey的JSON密钥枚举
enum UserInfoCodingKey: String, CodingKey {
case name
case password
case emailId
}
实施init
required init(from decoder: Decoder) throws
全班看起来像:
呼叫解码器
// jsonData是JSON响应,我们得到userInfo对象
let userInfo = try JsonDecoder().decode(UserInfo.self, from: jsonData)
答案 11 :(得分:1)
这种方式可让您从URL获取用户。它将NSData解析为NSDictionary,然后解析为您的NSObject。
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
}
答案 12 :(得分:0)
您可以使用 NSJSONSerialization 来完成此操作。其中数据是您的JSON。
首先将其包装在if语句中以提供一些错误处理功能
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)")
取自此Swift Parse JSON教程。您应该查看教程,因为它更深入,并涵盖更好的错误处理。