2
votes

Problème d'analyse codable

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.


0 commentaires

3 Réponses :


3
votes

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


4 commentaires

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.



1
votes
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let responseModel = try decoder.decode(Events.self, from: data) // data from response 

2 commentaires

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



0
votes

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 type Double par défaut. Le supposer directement comme une chaîne n'est pas acceptable dans swift.


0 commentaires