Etape suivante : prends l'habitude de donner des noms descriptifs à tes variables. Tu le fais en partie dans ce code, mais il reste encore un ui_pric1 et un pr dont la signification n'est pas évidente au premier regard.
Je présume que pr est un label. Tu devrais l'appeler labelPrice.
Tu es sûr que la valeur dans le dictionnaire est bien un String ? Elle n'est pas vraiment un Double ou un NSNumber ? Tu as, auparavant, montré du code qui dit que le dictionnaire est [String : AnyObject] ; du coup, il n'est pas possible de stocker un String là dedans.
Les seuls types que l'on puisse stocker dans un NSDictionary sont : NSArray, NSDictionary, NSString, NSData, NSDate et NSNumber.
Je t'emmène à ton code pour récupérer le dictionnaire d'un objet Data :
let jsonData:NSDictionary = try JSONSerialization.jsonObject(with: urlData!, options:JSONSerialization.ReadingOptions.mutableContainers ) as! NSDictionary
Dans un mot - Wuaaaarrrgghhhh !!! Tu as, encore un fois, fait les suppositions sans faisant les vérifications.
Voici du code qui essaie de réagir à toutes les possibilités :
func test()
{
do
{
let jsonObject = try JSONSerialization.jsonObject(with: data, options: []) // aucun besoin pour les options
// si l'appel à JSONSerialization.jsonObject s'échouait, on va directement d'ici au catch
// tous le code suivant sera ignoré
guard let person = jsonObject as? [String : NSObject] else
{
// le jsonObject n'est pas un NSDictionary, autrement dit [String : NSObject]
// montrer qqch pour l'éxpliquer
return
}
// d'ici tu es sûr d'avoir un bon dictionnaire
guard let priceAsNSObject = person["price"] else
{
// aucune valeur trouvé pour le clé "price"
labelPrice.text = "pas de prix"
return
}
// même si la valeur n'est pas nil, elle pourrait être NSNull
// il faut les deux tests
if priceAsNSObject is NSNull
{
// valeur trouvé mais c'est NSNull
labelPrice.text = "pas de prix"
return
}
if let priceAsNumber = priceAsNSObject as? NSNumber
{
// valeur trouvé est un NSNumber
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.maximumFractionDigits = 0
formatter.locale = Locale(identifier: "fr_FR") // seulement si le prix est garanti d'être en €
fatalError("") // si tu arrivais ici, tu aurais un gros problème inattendu
}
catch
{
// montrer qqch pour dire que l'objet récupéré n'est pas du JSON malformé
}
}
Dans ce cas là , il n'y a pas les court-circuits.
Tu comprends le code que j'ai écrit dessus ? Sinon, il faut que tu demandes les précisions
Le top level doit être obligatoirement un NSArray ou un NSDictionary et les clés de NSDictionary sont des NSString.
Tout ça, c'est marqué dans la doc.
Par contre, si on utilise du Swift 3, il est fortement conseillé d'utiliser des Array et des Dictionary (Swift Type, donc des trucs du style [String:Any] ou [Any], etc.) plutôt que des NSDictionary et NSArray. Dès lors, déjà tu évites le mutableContainer.
Le top level doit être obligatoirement un NSArray ou un NSDictionary et les clés de NSDictionary sont des NSString.
Tout à fait.
Par contre, si on utilise du Swift 3, il est fortement conseillé d'utiliser des Array et des Dictionary (Swift Type, donc des trucs du style [String:Any] ou [Any], etc.) plutôt que des NSDictionary et NSArray. Dès lors, déjà tu évites le mutableContainer.
Bien sûr. Mais easyd a utilisé NSDictionary pour décoder le JSON et je lui ai montré l'équivalent le plus exacte, pour ses besoins, qui est [String : NSObject] ou, peut-être, j'aurais pu mis [String : AnyObject].
Surtout, pour easyd, il s'agit de faire les explications les moins compliquées 8--)
Réponses
Etape suivante : prends l'habitude de donner des noms descriptifs à tes variables. Tu le fais en partie dans ce code, mais il reste encore un ui_pric1 et un pr dont la signification n'est pas évidente au premier regard.
Je présume que pr est un label. Tu devrais l'appeler labelPrice.
Toujours beaucoups d'erreurs
Je déjeune mais après j'achèverai une bonne version
!!!!!!!!!! !
Je vais m'être cela au claire et que cela soit plus lisible.
Des questions :
Tu es sûr que la valeur dans le dictionnaire est bien un String ? Elle n'est pas vraiment un Double ou un NSNumber ? Tu as, auparavant, montré du code qui dit que le dictionnaire est [String : AnyObject] ; du coup, il n'est pas possible de stocker un String là dedans.
Les seuls types que l'on puisse stocker dans un NSDictionary sont : NSArray, NSDictionary, NSString, NSData, NSDate et NSNumber.
Je t'emmène à ton code pour récupérer le dictionnaire d'un objet Data :
Dans un mot - Wuaaaarrrgghhhh !!! Tu as, encore un fois, fait les suppositions sans faisant les vérifications.
Voici du code qui essaie de réagir à toutes les possibilités :
Dans ce cas là , il n'y a pas les court-circuits.
Tu comprends le code que j'ai écrit dessus ? Sinon, il faut que tu demandes les précisions
Euh... Non.
La "seule" restriction d'un NSDictionary, c'est d'avoir une clé qui est conforme à NSCopy et des valeurs non-nil (quand tu fais un setObject:ForKey:).
Par contre, dans un JSON, ce qu'il y aura :
NSDictionary, NSArray, NSString, NSNumber et/ou NSNull.
Le top level doit être obligatoirement un NSArray ou un NSDictionary et les clés de NSDictionary sont des NSString.
Tout ça, c'est marqué dans la doc.
Par contre, si on utilise du Swift 3, il est fortement conseillé d'utiliser des Array et des Dictionary (Swift Type, donc des trucs du style [String:Any] ou [Any], etc.) plutôt que des NSDictionary et NSArray. Dès lors, déjà tu évites le mutableContainer.
Oui, tu as raison mais je voulais le simplifier pour easyd :-*
Tout à fait.
Bien sûr. Mais easyd a utilisé NSDictionary pour décoder le JSON et je lui ai montré l'équivalent le plus exacte, pour ses besoins, qui est [String : NSObject] ou, peut-être, j'aurais pu mis [String : AnyObject].
Surtout, pour easyd, il s'agit de faire les explications les moins compliquées 8--)