Swift 中对象的自动 JSON 序列化和反序列化

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26820720/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 17:37:15  来源:igfitidea点击:

Automatic JSON serialization and deserialization of objects in Swift

jsonserializationswift

提问by Marius Schulz

I'm looking for a way to automatically serialize and deserialize class instances in Swift. Let's assume we have defined the following class …

我正在寻找一种在 Swift 中自动序列化和反序列化类实例的方法。假设我们已经定义了以下类……

class Person {
    let firstName: String
    let lastName: String

    init(firstName: String, lastName: String) {
        self.firstName = firstName
        self.lastName = lastName
    }
}

… and Personinstance:

...和Person实例:

let person = Person(firstName: "John", lastName: "Doe")

The JSON representation of personwould be the following:

的 JSON 表示person如下:

{
    "firstName": "John",
    "lastName": "Doe"
}

Now, here are my questions:

现在,这是我的问题:

  1. How can I serialize the personinstance and get the above JSON without having to manually add all properties of the class to a dictionary which gets turned into JSON?
  2. How can I deserialize the above JSON and get back an instantiated object that is statically typed to be of type Person? Again, I don't want to map the properties manually.
  1. 如何序列化person实例并获取上述 JSON,而不必手动将类的所有属性添加到字典中,该字典会变成 JSON?
  2. 如何反序列化上述 JSON 并取回静态类型为类型的实例化对象Person?同样,我不想手动映射属性。


Here's how you'd do that in C# using Json.NET:

以下是使用Json.NET在 C# 中执行此操作的方法:

var person = new Person("John", "Doe");
string json = JsonConvert.SerializeObject(person);
// {"firstName":"John","lastName":"Doe"}

Person deserializedPerson = JsonConvert.DeserializeObject<Person>(json);

采纳答案by Alex Nolasco

As indicated in WWDC2017@ 24:48 (Swift 4), we will be able to use the Codable protocol. Example

WWDC2017@ 24:48 ( Swift 4) 中所述,我们将能够使用 Codable 协议。例子

public struct Person : Codable {
   public let firstName:String
   public let lastName:String
   public let location:Location
}

To serialize

序列化

let payload: Data = try JSONEncoder().encode(person)

To deserialize

反序列化

let anotherPerson = try JSONDecoder().decode(Person.self, from: payload)

Note that all properties must conform to the Codable protocol.

请注意,所有属性都必须符合 Codable 协议。

An alternativecan be JSONCodablewhich is used by Swagger'scode generator.

一个替代方案可以是JSONCodable其用于通过扬鞭的代码生成器。

回答by Edwin Vermeer

You could use EVReflectionfor that. You can use code like:

您可以为此使用EVReflection。您可以使用以下代码:

var person:Person = Person(json:jsonString)

or

或者

var jsonString:String = person.toJsonString()

See the GitHub page for more detailed sample code. You only have to make EVObject the base class of your data objects. No mapping is needed (as long as the json keys are the same as the property names)

有关更详细的示例代码,请参阅 GitHub 页面。你只需要让 EVObject 成为你的数据对象的基类。不需要映射(只要 json 键与属性名称相同)

Update:Swift 4 has support for Codable which makes it almost as easy as EVReflection but with better performance. If you do want to use an easy contractor like above, then you could use this extension: Stuff/Codable

更新:Swift 4 支持 Codable,这使得它几乎和 EVReflection 一样简单,但性能更好。如果您确实想使用像上面这样的简单承包商,那么您可以使用此扩展程序:Stuff/Codable

回答by Imanou Petit

With Swift 4, you simply have to make your class conform to Codable(Encodableand Decodableprotocols) in order to be able to perform JSON serialization and deserialization.

使用 Swift 4,您只需让您的类符合CodableEncodableDecodable协议),以便能够执行 JSON 序列化和反序列化。

import Foundation

class Person: Codable {
    let firstName: String
    let lastName: String

    init(firstName: String, lastName: String) {
        self.firstName = firstName
        self.lastName = lastName
    }
}

Usage #1 (encode a Personinstance into a JSON string):

用法 #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"
 }
 */

Usage #2 (decode a JSON string into a Personinstance):

用法 #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"
 */

回答by nhgrif

There is a Foundation class called NSJSONSerializationwhich can do conversion to and from JSON.

有一个叫做 Foundation 的类NSJSONSerialization,它可以进行与JSON.

The method for converting from JSON to an object looks like this:

从 JSON 转换为对象的方法如下所示:

let jsonObject = NSJSONSerialization.JSONObjectWithData(data, 
    options: NSJSONReadingOptions.MutableContainers, 
    error: &error) as NSDictionary

Note that the first argument to this method is the JSONdata, but not as a string object, instead as a NSDataobject (which is how you'll often times get JSON data anyway).

请注意,此方法的第一个参数是JSON数据,但不是作为字符串对象,而是作为NSData对象(无论如何,这就是您经常获取 JSON 数据的方式)。

You most likely will want a factory method for your class that takes JSON data as an argument, makes use of this method and returns an initialize object of your class.

您很可能需要为您的类使用一个工厂方法,该方法将 JSON 数据作为参数,使用此方法并返回您的类的初始化对象。

To inverse this process and create JSON data out of an object, you'll want to make use of dataWithJSONObject, in which you'll pass an object that can be converted into JSON and have an NSData?returned. Again, you'll probably want to create a helper method that requires no arguments as an instance method of your class.

要反转此过程并从对象中创建 JSON 数据,您需要使用dataWithJSONObject,您将在其中传递一个可以转换为 JSON 并NSData?返回的对象。同样,您可能希望创建一个不需要参数的辅助方法作为类的实例方法。



As far as I know, the easiest way to handle this is to create a way to map your objects properties into a dictionary and pass that dictionary for turning your object into JSON data. Then when turning your JSON data into the object, expect a dictionary to be returned and reverse the mapping process. There may be an easier way though.

据我所知,处理这个问题的最简单方法是创建一种将对象属性映射到字典并传递该字典以将对象转换为 JSON 数据的方法。然后在将您的 JSON 数据转换为对象时,期望返回一个字典并反转映射过程。不过可能有更简单的方法。

回答by Penkey Suresh

You can achieve this by using ObjectMapperlibrary. It'll give you more control on variable names and the values and the prepared JSON. After adding this library extend the Mappableclass and define mapping(map: Map)function.

您可以通过使用ObjectMapper库来实现这一点。它将让您更好地控制变量名称和值以及准备好的 JSON。添加此库后,扩展Mappable类并定义mapping(map: Map)函数。

For example

例如

   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"]
       }

    }

Use it like below

像下面一样使用它

   let user = Mapper<User>().map(JSONString)

回答by Eddy Liu

First, create a Swift object like this

首先,像这样创建一个 Swift 对象

struct Person {
    var firstName: String?;
    var lastName: String?;
    init() {

    }
}

After that, serialize your JSON data you retrieved, using the built-in NSJSONSerializationand parse the values into the Personobject.

之后,使用内置的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;
}

UPDATE:

更新:

Also please take a look at those libraries

也请看看那些图书馆

Swift-JsonSerialiser

Swift-JsonSerialiser

ROJSONParser

ROJSON解析器

回答by simplatek

Take a look at NSKeyValueCoding.h, specifically setValuesForKeysWithDictionary. Once you deserialize the json into a NSDictionary, you can then create and initialize your object with that dictionary instance, no need to manually set values on the object. This will give you an idea of how the deserialization could work with json, but you will soon find out you need more control over deserialization process. This is why I implement a category on NSObjectwhich allows fully controlled NSObjectinitialization with a dictionary during json deserialization, it basically enriches the object even further than setValuesForKeysWithDictionarycan do. I also have a protocol used by the json deserializer, which allows the object being deserialized to control certain aspects, for example, if deserializing an NSArray of objects, it will ask that object what is the type name of the objects stored in the array.

看看 NSKeyValueCoding.h,特别是setValuesForKeysWithDictionary. 一旦您将 json 反序列化为NSDictionary,您就可以使用该字典实例创建和初始化您的对象,而无需在对象上手动设置值。这将使您了解反序列化如何与 json 一起工作,但您很快就会发现您需要对反序列化过程进行更多控制。这就是为什么我实现了一个类别NSObject,允许NSObject在 json 反序列化期间使用字典完全控制初始化,它基本上比setValuesForKeysWithDictionary可以做。我还有一个 json 反序列化器使用的协议,它允许被反序列化的对象控制某些方面,例如,如果反序列化一个 NSArray 对象,它会询问该对象存储在数组中的对象的类型名称是什么。