J'essaie d'analyser la réponse de l'API en utilisant la classe Codable.
Voici la réponse:
struct Events: Codable { var event_id: String var event_name: String var event_desc: String var from_date: String var to_date: String var bar_id: String var bar_names: String var bar_ids: String var offer_image: String var from_time: String var to_time: String enum CodingKeys: String, CodingKey { case event_id = "event_id" case event_name = "event_name" case event_desc = "event_desc" case from_date = "from_date" case to_date = "to_date" case bar_id = "bar_id" case bar_names = "bar_names" case bar_ids = "bar_ids" case offer_image = "offer_image" case from_time = "from_time" case to_time = "to_time" } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(event_id, forKey: .event_id) try container.encode(event_name, forKey: .event_name) try? container.encode(event_desc, forKey: .event_desc) try? container.encode(from_date, forKey: .from_date) try container.encode(to_date, forKey: .to_date) try container.encode(bar_id, forKey: .bar_id) try container.encode(bar_names, forKey: .bar_names) try container.encode(bar_ids, forKey: .bar_ids) try container.encode(offer_image, forKey: .offer_image) try container.encode(from_time, forKey: .from_time) try container.encode(to_time, forKey: .to_time) } init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self) event_id = try values.decode(String.self, forKey: .event_id) event_name = try values.decode(String.self, forKey: .event_name) event_desc = try values.decode(String.self, forKey: .event_desc) from_date = try values.decode(String.self, forKey: .from_date) to_date = try values.decode(String.self, forKey: .to_date) bar_id = try values.decode(String.self, forKey: .bar_id) bar_names = try values.decode(String.self, forKey: .bar_names) bar_ids = try values.decode(String.self, forKey: .bar_ids) offer_image = try values.decode(String.self, forKey: .offer_image) from_time = try values.decode(String.self, forKey: .from_time) to_time = try values.decode(String.self, forKey: .to_time) } }
I La classe Codable est:
{"status":200,"message":"","success":1,"data":[{"event_id":"26","event_name":"Mens Night","event_desc":"Hot Mens Night","from_date":"2019-02-08","to_date":"2019-03-09","bar_id":"62","bar_names":"Autumn Bar & Bistro","bar_ids":"62","offer_image":"https:\/\/www.tippler.app\/manager\/uploads\/events\/mens_night.jpg","from_time":"19:00:00","to_time":"01:30:00"},{"event_id":"36","event_name":"Karaoke Night","event_desc":"Karaoke NIght with Brian Rub","from_date":"2019-02-08","to_date":"2019-02-09","bar_id":"146","bar_names":"Amuse Resto Bar","bar_ids":"146","offer_image":"https:\/\/www.tippler.app\/manager\/uploads\/events\/Screenshot_20190208-155223__011.jpg","from_time":"21:00:00","to_time":"01:00:00"},{"event_id":"37","event_name":"Sufi Nights","event_desc":"Singers From mumbai","from_date":"2019-02-08","to_date":"2019-02-09","bar_id":"66","bar_names":"Cavalry The Lounge","bar_ids":"66","offer_image":"https:\/\/www.tippler.app\/manager\/uploads\/events\/SUFI-FEATURED.jpg","from_time":"20:00:00","to_time":"01:30:00"},{"event_id":"39","event_name":"BOLLYWOOD NIGHT","event_desc":"BHANGRA AND LIVE DHOL","from_date":"2019-02-09","to_date":"2019-02-10","bar_id":"103","bar_names":"B Desi","bar_ids":"103","offer_image":"https:\/\/www.tippler.app\/manager\/uploads\/events\/bollywood-nights-1.jpg","from_time":"21:00:00","to_time":"01:00:00"}],"error_dev":""}
Il revient avec l'erreur de réponse
keyNotFound (CodingKeys (stringValue: "event_id", intValue: nil), Swift.DecodingError.Context (chemin de codage: [CodingKeys> (stringValue: "data", intValue: nil), _JSONKey (stringValue: "Index 0", intValue: 0)], debugDescription: "Aucune valeur associée à la clé CodingKeys (stringValue: \" event_id \ ", intValue: nil) (\ "event_id \"). ", sous-jacentError: nil))
Veuillez me suggérer la solution.
3 Réponses :
Votre structure codable ne correspond pas à la réponse car ils ont le statut, la réussite du message et la clé errorDev
Essayez ceci
struct GeneralResponse<T:Codable>: Codable { let status: Int? let message: String? let success: Int? let data: T? let errorDev: String? enum CodingKeys: String, CodingKey { case message = "msg" case code = "code" case data = "data" // add more keys } public init(from decoder:Decoder) throws { let contaienr = try decoder.container(keyedBy: CodingKeys.self) message = try contaienr.decode(String.self, forKey: .message) // Decode Other keys do { let object = try contaienr.decodeIfPresent(T.self, forKey: .data) data = object } catch { data = nil } } }
EDIT p>
Je peux vous fournir une solution plus générique. Supposons que toutes les API aient la même réponse mais que seule la clé data
est différente alors
struct Response: Codable { let status: Int? let message: String? let success: Int? let data: [Events]? let errorDev: String? enum CodingKeys: String, CodingKey { case status, message, success, data case errorDev = "error_dev" } } struct Events: Codable { let eventID, eventName, eventDesc, fromDate: String? let toDate, barID, barNames, barIDs: String? let offerImage: String? let fromTime, toTime: String? enum CodingKeys: String, CodingKey { case eventID = "event_id" case eventName = "event_name" case eventDesc = "event_desc" case fromDate = "from_date" case toDate = "to_date" case barID = "bar_id" case barNames = "bar_names" case barIDs = "bar_ids" case offerImage = "offer_image" case fromTime = "from_time" case toTime = "to_time" } }
Maintenant pour chaque réponse que vous pouvez
utiliser GenericResponse>
ou GenericResponse
ou GenericResponse>
J'espère que c'est utile
C'est une très mauvaise suggestion de déclarer tous les membres de la structure de manière schématique et irréfléchie comme facultatifs.
@vadian Je ne comprends pas pourquoi, pourriez-vous s'il vous plaît expliquer cela
JSON envoyé par une API est en fait un format très fiable. Donc, vous devez d'abord déclarer tous les membres de la structure comme non facultatifs et attraper et corriger les erreurs pour les clés qui peuvent être manquantes en changeant le type en facultatif. Par contre si tout est optionnel et que quelque chose ne va pas, vous ne verrez rien et vous ne savez pas pourquoi. Et déballer des options qui ne sont jamais nil
est assez ennuyeux.
@vadian Oui, je comprends cela. Je préfère utiliser optionnel car il y a des chances que l'API n'envoie pas de paramètre (nul) donc au lieu de gérer l'erreur, je laisse codable continuer avec une valeur optionnelle ou nulle. et plus tard, je gère cela avec les champs obligatoires. et une autre chose est que l'API peut contenir de nombreux champs inutiles, de sorte qu'elle peut être trop longue pour gérer chaque champ. et avec facultatif, nous avons la garantie que l'application ne plantera jamais.
let decoder = JSONDecoder() decoder.keyDecodingStrategy = .convertFromSnakeCase let responseModel = try decoder.decode(Events.self, from: data) // data from response
C'est une très mauvaise suggestion de déclarer tous les membres de la structure de manière schématique et irréfléchie comme facultatifs.
il renvoie eventID et barID comme nil
Il y a quelques erreurs dans votre code comme suit ...
event_id
est de type String
dans votre code mais est de type Int
. bar_id
est de type String
dans votre code mais est de type Int
. bar_ids
est de type String
dans votre code mais est de type Int
. Vous devez corriger ces types de variables.
Remarque: Partout où vous trouvez un nombre en réponse, il sera de type
Int
, un nombre avec des points décimaux comme 12.123 alors s'il sera de typeDouble
par défaut. Le supposer directement comme une chaîne n'est pas acceptable dans swift.