2017-09-21 64 views
0

我想实现Swift 4的新的可解码协议,并有一些难以接近它。使用Swift 4的可解码协议嵌套JSON服务器响应

这是我的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

'另外,如果数据突然变成一个数组而不是一个对象会发生什么,我该如何支持这两种数据类型? - 使用enum关联你的类型值?一个用'array',另一个用'dictionary'。 – user28434

+0

您应该阅读Codable文档中的[Encoding and Decoding Custom Types](编码和解码自定义类型)(https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types),以了解如何编写镜像JSON表示的类型。大多数情况下,这涉及编写类型并符合Codable,其余部分应该为您完成。 –

回答

0

首先你可以创建一个扩展为一个帮手:

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? 
} 

现在你需要提取从你的回应你的数据字典和应用新的初始化方法:

if let dic = json["data"] as? [String: Any] { 
    let user: User = User(with: dic) 
    // Do stuff here 
} 

如果数据突然变成一个数组,你将不得不处理它的方式不同(如本例中的用户数组)

+0

请在评论中解释为什么我的回答不合适,因此我可以替换或改进它。谢谢 –

+0

我不知道谁低估了你的答案,但它不是我。我会在明天早上读它并尝试它。会让你知道它是怎么回事:) – EpicSyntax