J’essaie d’parsingr un json mais j’ai des difficultés avec les types de données et notamment le type de downcasting de type AnyObject.
Considérons le json suivant (c’est un extrait d’un json complet).
{ "weather": [ { "id":804, "main":"Clouds", "description":"overcast clouds", "icon":"04d" } ], }
Pour moi, le json peut être décrit comme suit:
- json: Dictionary of type [Ssortingng: AnyObject] (or NSDictionary, so = [NSObject, AnyObject] in Xcode 6 b3) - "weather": Array of type [AnyObject] (or NSArray) - Dictionary of type [Ssortingng: AnyObject] (or NSDictionary, so = [NSObject, AnyObject] in Xcode 6 b3)
Mon json est de type AnyObject! (J’utilise JSONObjectWithData
pour obtenir le JSON depuis une URL).
Je veux ensuite accéder au dictionnaire météo. Voici le code que j’ai écrit.
var localError: NSError? var json: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &localError) if let dict = json as? [Ssortingng: AnyObject] { if let weatherDictionary = dict["weather"] as? [AnyObject] { // Do stuff with the weatherDictionary } }
Voici l’erreur que j’ai eu
Playground execution failed: error: :28:56: error: '[AnyObject]' is not a subtype of '(Ssortingng, AnyObject)' if let weatherDictionary = dict["weather"] as? [AnyObject] {
Je ne comprends pas pourquoi dict [“weather”] est comparé à un sous-type de (Ssortingng, AnyObject) et non AnyObject.
J’ai déclaré mon dictionnaire comme [Ssortingng: AnyObject], donc j’accède à une valeur en utilisant la clé Ssortingng, je devrais avoir un AnyObject, non?
Si j’utilise NSDictionary à la place de [Ssortingng: AnyObject], cela fonctionne.
Si j’utilise NSArray au lieu de [AnyObject], cela fonctionne.
- The Xcode 6 beta 3 release notes tell that "NSDictionary* is now imported from Objective-C APIs as [NSObject : AnyObject].". - And the Swift book: "When you bridge from an NSArray object to a Swift array, the resulting array is of type [AnyObject]."
MODIFIER
J’ai oublié de forcer le déballage du dict [“météo”] !.
if let dict = json as? [Ssortingng: AnyObject] { println(dict) if let weatherDictionary = dict["weather"]! as? [AnyObject] { println("\nWeather dictionary:\n\n\(weatherDictionary)") if let descriptionSsortingng = weatherDictionary[0]["description"]! as? Ssortingng { println("\nDescription of the weather is: \(descriptionSsortingng)") } } }
Notez que nous devrions vérifier l’existence du premier facultatif.
if let dict = json as? [Ssortingng: AnyObject] { for key in ["weather", "traffic"] { if let dictValue = dict[key] { if let subArray = dictValue as? [AnyObject] { println(subArray[0]) } } else { println("Key '\(key)' not found") } } }
Cela fonctionne très bien pour moi dans la cour de récréation et dans le terminal en utilisant env xcrun swift
MISE À JOUR POUR SWIFT 4 ET CODABLE
Voici un exemple de Swift 4 utilisant le protocole Codable.
var jsonStr = "{\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],}" struct Weather: Codable { let id: Int let main: Ssortingng let description: Ssortingng let icon: Ssortingng } struct Result: Codable { let weather: [Weather] } do { let weather = try JSONDecoder().decode(Result.self, from: jsonStr.data(using: .utf8)!) print(weather) } catch { print(error) }
MISE À JOUR POUR SWIFT 3.0
J’ai mis à jour le code pour Swift 3 et a également montré comment envelopper le JSON analysé dans des objects. Merci pour tous les votes!
import Foundation struct Weather { let id: Int let main: Ssortingng let description: Ssortingng let icon: Ssortingng } extension Weather { init?(json: [Ssortingng: Any]) { guard let id = json["id"] as? Int, let main = json["main"] as? Ssortingng, let description = json["description"] as? Ssortingng, let icon = json["icon"] as? Ssortingng else { return nil } self.id = id self.main = main self.description = description self.icon = icon } } var jsonStr = "{\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],}" enum JSONParseError: Error { case notADictionary case missingWeatherObjects } var data = jsonStr.data(using: Ssortingng.Encoding.ascii, allowLossyConversion: false) do { var json = try JSONSerialization.jsonObject(with: data!, options: []) guard let dict = json as? [Ssortingng: Any] else { throw JSONParseError.notADictionary } guard let weatherJSON = dict["weather"] as? [[Ssortingng: Any]] else { throw JSONParseError.missingWeatherObjects } let weather = weatherJSON.flatMap(Weather.init) print(weather) } catch { print(error) }
– Réponse précédente –
import Foundation var jsonStr = "{\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],}" var data = jsonStr.dataUsingEncoding(NSASCIISsortingngEncoding, allowLossyConversion: false) var localError: NSError? var json: AnyObject! = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: &localError) if let dict = json as? [Ssortingng: AnyObject] { if let weather = dict["weather"] as? [AnyObject] { for dict2 in weather { let id = dict2["id"] let main = dict2["main"] let description = dict2["description"] println(id) println(main) println(description) } } }
Comme je reçois encore des votes pour cette réponse, j’ai pensé que je reviendrais le voir pour Swift 2.0:
import Foundation var jsonStr = "{\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],}" var data = jsonStr.dataUsingEncoding(NSASCIISsortingngEncoding, allowLossyConversion: false) do { var json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) if let dict = json as? [Ssortingng: AnyObject] { if let weather = dict["weather"] as? [AnyObject] { for dict2 in weather { let id = dict2["id"] as? Int let main = dict2["main"] as? Ssortingng let description = dict2["description"] as? Ssortingng print(id) print(main) print(description) } } } } catch { print(error) }
La plus grande différence est que la variable json
n’est plus un type facultatif et la syntaxe do / try / catch. Je suis également allé de l’avant et tapé id
, main
et description
.
Essayer:
Avec cela, vous pouvez aller comme ceci:
let obj:[Ssortingng:AnyObject] = [ "array": [JSON.null, false, 0, "", [], [:]], "object":[ "null": JSON.null, "bool": true, "int": 42, "double": 3.141592653589793, "ssortingng": "a α\t弾\n𪚲", "array": [], "object": [:] ], "url":"http://blog.livedoor.com/dankogai/" ] let json = JSON(obj) json.toSsortingng() json["object"]["null"].asNull // NSNull() json["object"]["bool"].asBool // true json["object"]["int"].asInt // 42 json["object"]["double"].asDouble // 3.141592653589793 json["object"]["ssortingng"].asSsortingng // "a α\t弾\n𪚲" json["array"][0].asNull // NSNull() json["array"][1].asBool // false json["array"][2].asInt // 0 json["array"][3].asSsortingng // ""
En utilisant ma bibliothèque ( https://github.com/isair/JSONHelper ), vous pouvez le faire avec votre variable json de type AnyObject:
var weathers = [Weather]() // If deserialization fails, JSONHelper just keeps the old value in a non-optional variable. This lets you assign default values like this. if let jsonDictionary = json as? JSONDictionary { // JSONDictionary is an alias for [Ssortingng: AnyObject] weathers <-- jsonDictionary["weather"] }
Si votre tableau n'avait pas été sous la clé "météo", votre code aurait été juste ceci:
var weathers = [Weather]() weathers <-- json
Ou, si vous avez une chaîne JSON dans vos mains, vous pouvez simplement la transmettre, au lieu de créer d'abord un dictionnaire JSON à partir de la chaîne. La seule configuration à effectuer consiste à écrire une classe ou une structure Weather:
struct Weather: Deserializable { var id: Ssortingng? var name: Ssortingng? var description: Ssortingng? var icon: Ssortingng? init(data: [Ssortingng: AnyObject]) { id <-- data["id"] name <-- data["name"] description <-- data["description"] icon <-- data["icon"] } }