我正在尝试实施Swift 4的新Decodable协议,并且很难接近它。
这是我的JSON服务器响应:
{
"success": true,
"errorCode": 0,
"message": "Succcess",
"data": {
"name": "Logan Howlett",
"nickname": "The Wolverine",
"image": "http://heroapps.co.il/employee-tests/ios/logan.jpg",
"dateOfBirth": 1880,
"powers": [
"Adamantium Bones",
"Self-Healing",
"Adamantium Claws"
],
"actorName": "Hugh Jackman",
"movies": [
{
"name": "X-Men Origins: Wolverine",
"year": 2009
},
{
"name": "The Wolverine",
"year": 2013
},
{
"name": "X-Men: Days of Future Past",
"year": 2014
},
{
"name": "Logan",
"year": 2017
},
]
}
}
解码响应data
部分的最佳方法是什么?
此外,如果data
突然变为array
而不是对象,会发生什么情况,我如何支持这两种数据类型?
非常感谢:)
答案 0 :(得分:2)
首先,您可以创建一个扩展名作为帮助者:
extension Data {
func decode <Generic: Codable> () -> Generic? {
let decoder = JSONDecoder()
let object = try? decoder.decode(Generic.self, from: self)
return object
}
}
extension Dictionary {
func decode <Generic: Codable> () -> Generic? {
let data = try? JSONSerialization.data(withJSONObject: self,
options: JSONSerialization.WritingOptions.prettyPrinted)
guard let d = data else {
return nil
}
return d.decode()
}
}
然后,您可以创建协议来帮助您构建对象:
protocol Encode: Codable {
init(with dictionary: [String: Any])
init(with data: Data)
}
使用默认实现:
extension Encode {
init(with data: Data) {
let object: Self? = data.decode()
guard let obj = object else {
fatalError("fail to init object with \(data)")
}
self = obj
}
init(with dictionary: [String: Any]) {
let object: Self? = dictionary.decode()
guard let obj = object else {
fatalError("fail to init object with \(dictionary)")
}
self = obj
}
然后将对象创建为符合y Codable
协议的结构。它看起来像:
struct User: Codable {
var name: String?
var nickname: String?
...
// If needed declare CodingKey here
// enum CodingKeys: String, CodingKey {
// case date = "dateOfBirth"
// ...
// }
}
struct Movies: Codable {
var name: String?
var year: Int?
}
现在,您需要从响应中提取数据字典并应用新的init方法:
if let dic = json["data"] as? [String: Any] {
let user: User = User(with: dic)
// Do stuff here
}
如果数据突然成为一个数组,则必须以不同的方式处理它(在此示例中为用户数组)