我正在寻找一种在Swift中自动序列化和反序列化类实例的方法。我们假设我们已经定义了以下类......
class Person {
let firstName: String
let lastName: String
init(firstName: String, lastName: String) {
self.firstName = firstName
self.lastName = lastName
}
}
...和Person
实例:
let person = Person(firstName: "John", lastName: "Doe")
person
的JSON表示如下:
{
"firstName": "John",
"lastName": "Doe"
}
现在,我的问题是:
person
实例并获取上述JSON,而无需手动将类的所有属性添加到转换为JSON的字典中?Person
类型的实例化对象?同样,我不想手动映射属性。以下是使用Json.NET在C#中执行此操作的方法:
var person = new Person("John", "Doe");
string json = JsonConvert.SerializeObject(person);
// {"firstName":"John","lastName":"Doe"}
Person deserializedPerson = JsonConvert.DeserializeObject<Person>(json);
答案 0 :(得分:26)
如WWDC2017 @ 24:48( Swift 4 )所示,我们将能够使用Codable协议。实施例
public struct Person : Codable {
public let firstName:String
public let lastName:String
public let location:Location
}
序列化
let payload: Data = try JSONEncoder().encode(person)
反序列化
let anotherPerson = try JSONDecoder().decode(Person.self, from: payload)
请注意,所有属性都必须符合Codable协议。
替代可以是JSONCodable代码生成器使用的Swagger's。
答案 1 :(得分:20)
您可以使用EVReflection。您可以使用以下代码:
var person:Person = Person(json:jsonString)
或
var jsonString:String = person.toJsonString()
有关更详细的示例代码,请参阅GitHub页面。您只需将EVObject作为数据对象的基类。不需要映射(只要json键与属性名称相同)
更新:Swift 4支持Codable,这使得它几乎像EVReflection一样简单,但具有更好的性能。如果您确实想使用上述简易承包商,那么您可以使用此扩展程序:Stuff/Codable
答案 2 :(得分:8)
使用Swift 4,您只需使您的类符合Codable
(Encodable
和Decodable
协议),以便能够执行JSON序列化和反序列化。
import Foundation
class Person: Codable {
let firstName: String
let lastName: String
init(firstName: String, lastName: String) {
self.firstName = firstName
self.lastName = lastName
}
}
用法#1(将Person
实例编码为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"
}
*/
用法#2(将JSON字符串解码为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"
*/
答案 3 :(得分:5)
有一个名为NSJSONSerialization
的基础课程,可以与JSON
进行转换。
从JSON转换为对象的方法如下所示:
let jsonObject = NSJSONSerialization.JSONObjectWithData(data,
options: NSJSONReadingOptions.MutableContainers,
error: &error) as NSDictionary
请注意,此方法的第一个参数是JSON
数据,但不是作为字符串对象,而是作为NSData
对象(这是您经常获取JSON数据的方式)
您很可能需要一个以JSON数据作为参数的类的工厂方法,使用此方法并返回类的初始化对象。
要反转此过程并从对象中创建JSON数据,您需要使用dataWithJSONObject
,其中您将传递一个可转换为JSON且具有{{1}的对象}} 回。同样,您可能希望创建一个不需要参数作为类的实例方法的辅助方法。
据我所知,处理此问题的最简单方法是创建一种方法将对象属性映射到字典中,并传递该字典以将对象转换为JSON数据。然后,当您将JSON数据转换为对象时,期望返回字典并反转映射过程。可能有一种更简单的方法。
答案 4 :(得分:4)
您可以使用ObjectMapper库来实现此目的。它将为您提供对变量名称,值以及准备好的JSON的更多控制权。添加此库后,扩展Mappable
类并定义mapping(map: Map)
函数。
例如
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"]
}
}
使用如下
let user = Mapper<User>().map(JSONString)
答案 5 :(得分:0)
首先,创建一个像这样的Swift对象
struct Person {
var firstName: String?;
var lastName: String?;
init() {
}
}
之后,使用内置的 NSJSONSerialization 序列化您检索到的JSON数据,并将值解析为 Person 对象。
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;
}
<强>更新强>
另请查看这些库
答案 6 :(得分:0)
看看NSKeyValueCoding.h,特别是setValuesForKeysWithDictionary
。将json反序列化为NSDictionary
后,可以使用该字典实例创建和初始化对象,无需在对象上手动设置值。这将让您了解反序列化如何与json一起使用,但您很快就会发现需要对反序列化过程进行更多控制。这就是我在NSObject
上实现一个类别的原因,它允许在json反序列化期间使用字典进行完全控制的NSObject
初始化,它基本上比setValuesForKeysWithDictionary
更能使对象更加丰富。我还有一个json反序列化器使用的协议,它允许反序列化的对象控制某些方面,例如,如果反序列化NSArray对象,它将询问该对象什么是存储在数组中的对象的类型名称。