Swift 4 - 如何像Java中的Gson一样自动将Json转换为Swift对象

21

我是Swift 4的新手,正在尝试弄清楚如何自动将Json转换为Swift对象,就像在Java中使用Gson一样。是否有任何插件可以将我的Json转换为对象并进行相反的操作?我已经尝试使用SwiftyJson库,但无法理解直接将Json转换为对象映射器的语法。在Gson中,转换如下:

String jsonInString = gson.toJson(obj);
Staff staff = gson.fromJson(jsonInString, Staff.class);

你能否给像我这样的初学者建议一些非常简单的示例。以下是我的Swift个人类:

class Person  {
    let firstName: String
    let lastName: String

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

以下是从服务器获取响应的方法调用:

let response = Helper.makeHttpCall(url: "http://localhost:8080/HttpServices/GetBasicJson", method: "PUT", param: interestingNumbers)

我得到的响应变量是JSON:

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

2
Swift 4 引入了 Codable 协议和 JSONEncoder / JSONDecoder,用于此目的。这里是一个非常全面的关于此主题的指南。 - Alladinian
是的,似乎Codable是一个解决方案。但是,它仍然需要输入类型,不像Gson! - Markymark
2个回答

29
在 Swift 中,不再需要外部库。自从 Swift 4 开始,有两个协议可以实现你所需要的功能:DecodableEncodable,它们被分组到 Codable 类型别名中,以及 JSONDecoder
你只需要创建符合 Codable 的实体即可(在这个例子中,Decodable 足够了)。
struct Person: Codable {
    let firstName, lastName: String
}

// Assuming makeHttpCall has a callback:
Helper.makeHttpCall(url: "http://localhost:8080/HttpServices/GetBasicJson", method: "PUT", param: interestingNumbers, callback: { response in
    // response is a String ? Data ?
    // Assuming it's Data
    let person = try! decoder.decode(Person.self, for: response)

    // Uncomment if it's a String and comment the line before
    // let jsonData = response.data(encoding: .utf8)!
    // let person = try! decoder.decode(Person.self, for: jsonData)
    print(person)
})

更多信息:


没错,但是什么时候使用JSONArray呢?你需要将它包装在一个“JSONObject”中吗? - firetrap
不可以。您可以使用 let persons = try! decoder.decode([Person.self], for: response) - nathan
在这个实例中,什么是解码器?由于解码器是一个协议,因此可以进行实例化。展示您声明解码器的方式会大有帮助。 - paul_f
2
@paul_f 很晚才回复,但由于没有人回答,这可能会为其他人节省几分钟,解码器实例实际上是 let decoder = JSONDecoder()来源 - grill2010

2

正如 @nathan 建议的那样

“现在在Swift中不再需要外部库了。”

但是如果您仍然想使用第三方库,比如 ObjectMapper

class Person : Mappable {
    var firstName: String?
    var lastName: String?
    required init?(map:Map) {

    }

   func mapping(map:Map){
      //assuming the first_name and last_name is what you have got in JSON
      // e.g in android you do like @SerializedName("first_name") to map
     firstName <- map["first_name"]
     lastName <- map["last_name"]
   }

}




let person = Mapper<Person>().map(JSONObject:response.result.value)

扩展@nathan的答案,展示在iOS中使用Codable等效于@SerializedName注释的方法

struct Person : Codable {

        let firstName : String?
        let lastName : String?

        enum CodingKeys: String, CodingKey {
                case firstName = "first_name"
                case lastName = "last_name"
        }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接