Probleme avec format JSON

Bonjour, je veux récupérer des données via une adresse URL, par contre une des valeurs à récupérer est parfois un string « null » et parfois un Int. J’ai une erreur à tout coup, je ne sais pas comment géré ce problème (je suis relativement nouveau en prog) Mon programme est en SwiftUI et je n’ai rien trouvé comme solution sur internet.

Voici mon struct:
import Foundation

struct ProvinceData: Decodable {

var summary: [HealthProvData]

}

struct HealthProvData: Decodable{

var active_cases: Int
var active_cases_change: Int
var cases: Int
var cumulative_cases: Int
var cumulative_deaths: Int // problème parfois String parfois Int
var cumulative_recovered: Int
var cumulative_testing: Int // problème parfois String parfois Int
var date: String
var deaths: Int // problème parfois String parfois Int
var province: String
var recovered: Int
var testing: Int // problème parfois String parfois Int
var testing_info: String
}

et voici mon parser

func getProvinceData(date: Date) {
let urlString = « (baseUrl)(summaryUrl)(placeUrl)(dateForm(d: date)) »
print(urlString)
if let url = URL(string: urlString) {
URLSession.shared.dataTask(with: url) { (data, response, error) in
if let d = data {
do {
let result = try JSONDecoder().decode(ProvinceData.self, from: d)
DispatchQueue.main.async {
self.provinceDatas = result.summary
}
}
catch {
print(error)
}
}
}.resume()
}
}

Merci pour votre aide

Bonjour @flouby et bienvenue !

Est-il possible de voir ton fichier ou un extrait de ton fichier JSON? Dans les valeurs à récupérer, le format est bien toujours le même? Genre par exemple, tu peux avoir « Int » et parfois une valeur « String » dedans, ce qui te pose soucis ensuite à la lecture.
Si c’est le cas, il faut gérer l’exception je pense…

Bonjour,

oui je met le json au complet, comme vous pourrez le voir sur certaine province, les valeur sont string
{« summary »:[{« active_cases »:3651,« active_cases_change »:0,« cases »:0,« cumulative_cases »:24261,« cumulative_deaths »:300.0,« cumulative_recovered »:20310.0,« cumulative_testing »:1697849.0,« date »:« 25-10-2020 »,« deaths »:0.0,« province »:« Alberta »,« recovered »:0.0,« testing »:0.0,« testing_info »:« NULL »},{« active_cases »:2051,« active_cases_change »:0,« cases »:0,« cumulative_cases »:12554,« cumulative_deaths »:256.0,« cumulative_recovered »:10247.0,« cumulative_testing »:764099.0,« date »:« 25-10-2020 »,« deaths »:0.0,« province »:« BC »,« recovered »:0.0,« testing »:0.0,« testing_info »:« NULL »},{« active_cases »:2053,« active_cases_change »:131,« cases »:161,« cumulative_cases »:4249,« cumulative_deaths »:54.0,« cumulative_recovered »:2142.0,« cumulative_testing »:240639.0,« date »:« 25-10-2020 »,« deaths »:4.0,« province »:« Manitoba »,« recovered »:26.0,« testing »:4616.0,« testing_info »:« NULL »},{« active_cases »:65,« active_cases_change »:-7,« cases »:2,« cumulative_cases »:328,« cumulative_deaths »:6.0,« cumulative_recovered »:257.0,« cumulative_testing »:96747.0,« date »:« 25-10-2020 »,« deaths »:2.0,« province »:« New Brunswick »,« recovered »:7.0,« testing »:555.0,« testing_info »:« NULL »},{« active_cases »:11,« active_cases_change »:1,« cases »:1,« cumulative_cases »:290,« cumulative_deaths »:4.0,« cumulative_recovered »:275.0,« cumulative_testing »:50682.0,« date »:« 25-10-2020 »,« deaths »:0.0,« province »:« NL »,« recovered »:0.0,« testing »:227.0,« testing_info »:« NULL »},{« active_cases »:6,« active_cases_change »:0,« cases »:0,« cumulative_cases »:1100,« cumulative_deaths »:65.0,« cumulative_recovered »:1029.0,« cumulative_testing »:109790.0,« date »:« 25-10-2020 »,« deaths »:0.0,« province »:« Nova Scotia »,« recovered »:0.0,« testing »:403.0,« testing_info »:« NULL »},{« active_cases »:0,« active_cases_change »:0,« cases »:0,« cumulative_cases »:0,« cumulative_deaths »:0.0,« cumulative_recovered »:0.0,« cumulative_testing »:3464.0,« date »:« 25-10-2020 »,« deaths »:0.0,« province »:« Nunavut »,« recovered »:0.0,« testing »:0.0,« testing_info »:« NULL »},{« active_cases »:4,« active_cases_change »:0,« cases »:0,« cumulative_cases »:9,« cumulative_deaths »:0.0,« cumulative_recovered »:5.0,« cumulative_testing »:6149.0,« date »:« 25-10-2020 »,« deaths »:0.0,« province »:« NWT »,« recovered »:0.0,« testing »:0.0,« testing_info »:« NULL »},{« active_cases »:9549,« active_cases_change »:201,« cases »:943,« cumulative_cases »:72841,« cumulative_deaths »:3132.0,« cumulative_recovered »:60160.0,« cumulative_testing »:4908771.0,« date »:« 25-10-2020 »,« deaths »:6.0,« province »:« Ontario »,« recovered »:736.0,« testing »:38769.0,« testing_info »:« NULL »},{« active_cases »:1,« active_cases_change »:0,« cases »:0,« cumulative_cases »:64,« cumulative_deaths »:0.0,« cumulative_recovered »:63.0,« cumulative_testing »:42377.0,« date »:« 25-10-2020 »,« deaths »:0.0,« province »:« PEI »,« recovered »:0.0,« testing »:0.0,« testing_info »:« NULL »},{« active_cases »:9143,« active_cases_change »:-141,« cases »:879,« cumulative_cases »:100114,« cumulative_deaths »:6143.0,« cumulative_recovered »:84828.0,« cumulative_testing »:1846594.0,« date »:« 25-10-2020 »,« deaths »:11.0,« province »:« Quebec »,« recovered »:1009.0,« testing »:10673.0,« testing_info »:« NULL »},{« active_cases »:0,« active_cases_change »:0,« cases »:0,« cumulative_cases »:13,« cumulative_deaths »:« NULL »,« cumulative_recovered »:13.0,« cumulative_testing »:« NULL »,« date »:« 25-10-2020 »,« deaths »:« NULL »,« province »:« Repatriated »,« recovered »:0.0,« testing »:« NULL »,« testing_info »:« NULL »},{« active_cases »:619,« active_cases_change »:45,« cases »:60,« cumulative_cases »:2729,« cumulative_deaths »:25.0,« cumulative_recovered »:2085.0,« cumulative_testing »:199263.0,« date »:« 25-10-2020 »,« deaths »:0.0,« province »:« Saskatchewan »,« recovered »:15.0,« testing »:1766.0,« testing_info »:« NULL »},{« active_cases »:5,« active_cases_change »:0,« cases »:0,« cumulative_cases »:20,« cumulative_deaths »:0.0,« cumulative_recovered »:15.0,« cumulative_testing »:3857.0,« date »:« 25-10-2020 »,« deaths »:0.0,« province »:« Yukon »,« recovered »:0.0,« testing »:0.0,« testing_info »:« NULL »}]}

De ce que je vois, dans les variables « parfois Int, parfois String » c’est le format dans le fichier.
Dans ce que tu décris :
var cumulative_deaths: Int // problème parfois String parfois Int
var cumulative_testing: Int // problème parfois String parfois Int
var deaths: Int // problème parfois String parfois Int
var testing: Int // problème parfois String parfois Int

Tu notes que les données sont au format « 00.0 » et non « 00 », je pense que Swift ne le traite pas en Int. ce qui pose soucis.
Il doit considérer ces données en Double et non en Int, d’où les erreurs.
Faudrait les faire apparaitre en « 00 » et non en « 00.0 » en amont ou gérer ces cas pour ces variables. (si je ne dis pas de bétises)
Et effectivement on voit des « Null » apparaitre aussi. Faut gérer donc ces exceptions. (tu as un cours de Maxime sur les exceptions dans Swift POO il me semble).

Ok je vais regarder, c’est justement ça gérer l’exception que je ne sais pas comment et je ne trouve pas dans les cours de Maxime, si quelqu’un peut m’indiquer un peu ou chercher… Merci

C’est le point 6 - Gestion des cas d’erreurs, dans le cours « Apprendre la Programmation Orientée Objets (en Swift) ».

Il y a un truc que je ne comprends pas : comment une variable peut être parfois d’un type, parfois d’un autre ? Je peux comprendre un Int? optionnel et qui peut donc être nul, mais pas parfois String, parfois Int, le caméléon, c’est une autre émission ?? Non ?

en fait il y a une donnée dans le JSON qui est généralement un Int, mais parfois quand il n’y a rien au lieu d’envoyer un 0, il envoi la valeur « NULL » entre guillemet donc on le vois comme un String

J’ai regarder dans le video de formation de Maxime, et ça ne répond pas à mon problème, ce n’est pas une gestion d’erreur, l’erreur viens du fait que une des valeurs change de type dans le fichier JSON reçu, donc je dois faire quelques choses avant de le decoder pour géré cela, mais je ne sais pas comment

T’as essayé de définir testing comme une variable optionnelle (Int?), au lieu d’un simple Int ?

Pour autant que je comprenne le mécanisme de décodage de JSON, cela devrait te donner une valeur quand c’est un Int, et la valeur optionnelle NULL si c’est un String.

Ensuite, tu utilises un classique if let pour accéder à la valeur de testing.

C’est juste une idée, non testé.

oui, j’ai tester, et j’obtient la même erreur

ça veut dire quoi ça ? Quelle même erreur ? Tu ne donnes aucune information sur ce que se passe.

Le programme se crache ? Il s’affiche un message spécifique ? Un code d’erreur apparait ? Tu ne peux faire une copie d’écran pour nous montrer ce qui se produit concrètement ?

j’ai tout expliqué dans le début de mon message, dsl je croyais être clair. En fait les données ne se charge pas et ça me donne l’erreur suivante dans Xcode: typeMismatch(Swift.Int, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: « summary », intValue: nil), _JSONKey(stringValue: « Index 11 », intValue: 11), CodingKeys(stringValue: « testing », intValue: nil)], debugDescription: « Expected to decode Int but found a string/data instead. », underlyingError: nil))

sauf que le problème c’est le fichier JSON pour la valeur « testing » vaux parfois un chiffre et dans une autre valeur il vaut « NULL » qui est interpreter par le decodeur comme un String. Donc je ne sais pas comment gérer cette exeption pour pouvoir avoir les valeurs lier à testing. (tu peux voir mon fichier JSON plus haut dans le sujet) , en fait ce n’est pas que la valeur est juste abscente( dans ce cas je pourrais mettre un optionnel, c’est que la valeur null est insctrite en texte. Je ne sais pas si c’est plus clair

J’avais compris la nature du problème, mais le message d’erreur est important pour voir ce que Xcode ne comprend pas, lui … Le décodeur JSON est une boîte noire dont nous ne connaissons pas trop le fonctionnement interne.

Je te propose la chose suivante : considère que testing est une variable data optionnelle. Charge-la et essaie de la convertir en Int avec un if let ou un guard. Si ça marche, ton problème est résolu.

L’Idée était bonne, mais j’ai fait l’essai et ça m’inscrit

typeMismatch(Foundation.Data, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: « summary », intValue: nil), _JSONKey(stringValue: « Index 0 », intValue: 0), CodingKeys(stringValue: « testing », intValue: nil)], debugDescription: « Expected to decode Data but found a number instead. », underlyingError: nil))

Solution : écrire un parseur JSON à la main, celui intégré à iOS ne supportant pas ce format exotique. Bonne chance … * prend la fuite *

C’est une obligation pour toi, d’utiliser ce fichier bizarroïde, ou c’est un juste un échantillon de test, sans importance ?

non , ce n’est pas une obligation, c’était juste un défi que je tentais de relever… mais je commence à en avoir raz le bol de chercher :wink:

Laisse tomber, ce fichier ne respecte pas les normes JSON. Il y a tellement de choses à apprendre, que tu ne vas pas perdre du temps avec un truc bidouillé ne respectant pas le format standard d’échange de données.

Édit : A ton stade d’apprentissage, l’objectif est d’apprendre à utiliser les briques logicielles standards pour maîtriser les concepts de base. Plus tard, bien plus tard, tu pourras recréer des briques logicielles pour gérer des problèmes non triviaux comme lire un fichier de données ne respectant pas les formats habituels.