web-dev-qa-db-fra.com

Swift 4 Codable Array's

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.

13
Charlie Fish

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)

14
nathan

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)
        }
    }
0
abbawssdsad