J'ai donc un itinéraire API qui renvoie un tableau d'objets JSON. Par exemple:
[
{"firstname": "Tom", "lastname": "Smith", "age": 31},
{"firstname": "Bob", "lastname": "Smith", "age": 28}
]
J'essaie de voir comment utiliser la nouvelle fonctionnalité codable de Swift pour convertir ceux-ci en deux objets dans une classe. Donc, si j'ai une classe de personnes codable, j'aimerais prendre cette réponse et qu'elle me donne des objets de deux personnes.
J'utilise également Alamofire pour traiter les demandes.
Comment puis-je faire ceci? Jusqu'à présent, tout ce que j'ai vu concernant les éléments codables ne permet qu'un objet. Et je n'ai vu aucune intégration avec Alamofire ou un framework web.
Mise à jour concernant Alamofire 5: responseJSONDecodable
.
struct Person: Codable {
let firstName, lastName: String
let age: Int
enum CodingKeys : String, CodingKey {
case firstName = "firstname"
case lastName = "lastname"
case age
}
}
Alamofire.request(request).responseJSONDecodable { (response: DataResponse<Person>) in
print(response)
}
Alamofire 4 n’ajoutera pas de support Codable (voir # 2177 ), vous pouvez utiliser cette extension à la place: 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)
Exemple: http://Swift.sandbox.bluemix.net/#/repl/59a4b4fad129044611590820
Utilisation de CodableAlamofire:
let decoder = JSONDecoder()
Alamofire.request(url).responseDecodableObject(keyPath: nil, decoder: decoder) { (response: DataResponse<[Person]>) in
let persons = response.result.value
print(persons)
}
keypath
correspond au chemin où les résultats sont contenus dans la structure JSON. Par exemple:
{
"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
lève une exception)
J'ai réussi à sérialiser la réponse des données à des objets codables.
Comme tout, vous avez peut-être déjà appris à convertir un objet json [String: String]
. Cet objet json doit être converti en Data
à l'aide de json.data(using: .utf8)!
.
Avec Alamofire, il est facile d'obtenir ces données (ou au moins ce type de données a fonctionné pour moi, déjà compatible avec .utf8
chose), je peux simplement utiliser cette fonction déjà disponible.
func responseData(queue: DispatchQueue?, completionHandler: @escaping (DataResponse<Data>) -> Void) -> Self
Ensuite, utilisez simplement ces données comme entrée pour la Decoder
dans la completionHandler
let objek = try JSONDecoder().decode(T.self, from: data)
Vous pouvez également en faire une fonction de sérialisation générique, avec un petit tweak, à partir de la documentation
Sérialisation d'objet de réponse générique
à cette modification
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)
}
Exemple de structure
struct Fids: Codable {
var Status: Status?
var Airport: Airport?
var Record: [FidsRecord]
}
Utilisez la fonction de cette façon
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)
}
}