2017-08-29 95 views
7

所以我有一个返回JSON数组对象的API路由。例如:Swift 4 Codable Array的

[ 
    {"firstname": "Tom", "lastname": "Smith", "age": 31}, 
    {"firstname": "Bob", "lastname": "Smith", "age": 28} 
] 

我试图想象如何使用雨燕的新功能可编码为转换成那些两个对象中的一类。所以如果我有一个可编码的人类,我会想要采取这种反应,让它给我两个人的对象。

我还使用Alamofire来处理请求。

我该怎么做?到目前为止,我所看到的与可编译的东西相关的所有内容都只允许1个对象。我还没有看到与Alamofire或Web框架的整合。

+1

是你的问题是如何改变您到所提供的JSON数组Person(示例实体)?还是一个异构对象的数组? – nathan

+0

那么我知道如果我有'{“名字”:“汤姆”,“姓氏”:“史密斯”,“年龄”:31}'和一个人类我可以将JSON转换成Swift中的个人对象使用可编码。但是我不确定如果我拥有从Alamofire获得的JSON数组,我该如何做到这一点。 –

+0

我对Alamofire(或者这个库)并不熟悉,但是有https://github.com/Otbivnoe/CodableAlamofire –

回答

7

Alamofire现在不会添加Codable支持(请参阅#2177),您可以使用此扩展替代:https://github.com/Otbivnoe/CodableAlamofire

let jsonData = """ 
[ 
    {"firstname": "Tom", "lastname": "Smith", "age": 31}, 
    {"firstname": "Bob", "lastname": "Smith", "age": 28} 
] 
""".data(using: .utf8)! 

struct Person: Codable { 
    let firstName, lastName: String 
    let age: Int 

    enum CodingKeys : String, CodingKey { 
     case firstName = "firstname" 
     case lastName = "lastname" 
     case age 
    } 
} 

let decoded = try! JSONDecoder().decode([Person].self, from: jsonData) 

样品:http://swift.sandbox.bluemix.net/#/repl/59a4b4fad129044611590820

使用CodableAlamofire:

let decoder = JSONDecoder() 
Alamofire.request(url).responseDecodableObject(keyPath: nil, decoder: decoder) { (response: DataResponse<[Person]>) in 
    let persons = response.result.value 
    print(persons) 
} 

keypath对应于其中结果被包含在JSON结构的路径。 E.g:

{ 
    "result": { 
     "persons": [ 
      {"firstname": "Tom", "lastname": "Smith", "age": 31}, 
      {"firstname": "Bob", "lastname": "Smith", "age": 28} 
     ] 
    } 
} 

keypath =>results.persons

[ 
    {"firstname": "Tom", "lastname": "Smith", "age": 31}, 
    {"firstname": "Bob", "lastname": "Smith", "age": 28} 
] 

keypath =>nil(空keypath抛出异常)

+0

那么如果'jsonData'就像数组那样工作? –

+1

答复已更新。看看示例代码 – nathan

+0

非常详细的答案。非常感谢你。现在没有时间仔细阅读,但会在某个时候完成。非常感谢!!! –

0

我设法序列化到可编码对象的数据的响应。

例如,您可能已经熟悉转换json对象[String: String]。该json对象需要使用json.data(using: .utf8)!转换为Data

随着Alamofire,很容易获得这些数据(或者至少这类数据的工作对我来说,已经与.utf8东西兼容),我就可以用这个已经存在的功能

func responseData(queue: DispatchQueue?, completionHandler: @escaping (DataResponse<Data>) -> Void) -> Self 

然后,只需使用该数据作为输入的DecodercompletionHandler

let objek = try JSONDecoder().decode(T.self, from: data) 

您也可以让这对一些通用的序列化功能,具有小调整,从文档

Generic Response Object Serialization

此修改

func responseCodable<T: Codable>(
    queue: DispatchQueue? = nil, 
    completionHandler: @escaping (DataResponse<T>) -> Void) 
    -> Self 
{ 
    let responseSerializer = DataResponseSerializer<T> { request, response, data, error in 
     guard error == nil else { return .failure(BackendError.network(error: error!)) } 

     guard let data = data else { 
      return .failure(BackendError.objectSerialization(reason: "data is not valid")) 
     } 


     do{ 
      let objek = try JSONDecoder().decode(T.self, from: data!) 
      return .success(objek) 
     } catch let e { 
      return .failure(BackendError.codableSerialization(error: e)) 
     } 

    } 

    return response(queue: queue, responseSerializer: responseSerializer, completionHandler: completionHandler) 
} 

样品结构

struct Fids: Codable { 

    var Status: Status? 
    var Airport: Airport? 
    var Record: [FidsRecord] 
} 

使用功能这样

Alamofire.request("http://whatever.com/zzz").responseCodable { (response: DataResponse<Fids>) in 
     switch response.result{ 
     case .success(let value): 
      print(value.Airport) 
     // MARK: do whatever you want 
     case .failure(let error): 
      print(error) 
      self.showToast(message: error.localizedDescription) 
     } 
    } 
+0

与接受的答案相比,你的答案有什么独特之处? –

+0

你不需要扩展或任何东西。我的意思是仅仅使用现有函数中的数据响应非常简单。对于已经使用Alamofire的人来说,这是一个简单的选择。对? – abbawssdsad

+0

是的。那么在做更多的研究后,有更好的方法来处理这个问题。添加responseCodable我觉得只是增加了复杂性。我也会争辩说我的主要问题是关于Swift 4 Codable Arrays。不是Alamofire。虽然我提到Alamofire,这不是我的主要问题。 –