parse jsonserialization how from data array json parsing swift

jsonserialization - Parse json en Swift, tipo AnyObject



swift 4 json to object (3)

Estoy tratando de analizar un json, pero tengo algunas dificultades con los tipos de datos y, notablemente, el tipo AnyObject + downcasting.

Consideremos el siguiente json (es un extracto de un json completo).

{ "weather": [ { "id":804, "main":"Clouds", "description":"overcast clouds", "icon":"04d" } ], }

Para mí, el json se puede describir de la siguiente manera:

- json: Dictionary of type [String: AnyObject] (or NSDictionary, so = [NSObject, AnyObject] in Xcode 6 b3) - "weather": Array of type [AnyObject] (or NSArray) - Dictionary of type [String: AnyObject] (or NSDictionary, so = [NSObject, AnyObject] in Xcode 6 b3)

¡Mi json es del tipo AnyObject! (Utilizo JSONObjectWithData para obtener el JSON de una URL).

Entonces quiero acceder al Diccionario meteorológico. Aquí está el código que escribí.

var localError: NSError? var json: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &localError) if let dict = json as? [String: AnyObject] { if let weatherDictionary = dict["weather"] as? [AnyObject] { // Do stuff with the weatherDictionary } }

Aquí está el error que obtuve

Playground execution failed: error: <EXPR>:28:56: error: ''[AnyObject]'' is not a subtype of ''(String, AnyObject)'' if let weatherDictionary = dict["weather"] as? [AnyObject] {

No entiendo por qué dict ["clima"] se compara con un subtipo de (String, AnyObject) y no AnyObject.

Decidí que mi diccionario era [String: AnyObject], así que accedí a un valor con la tecla String, debería tener AnyObject, ¿no?

Si uso NSDictionary en lugar de [String: AnyObject], funciona.

Si uso NSArray en lugar de [AnyObject], funciona.

- 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]."

EDITAR

Me olvidé de obligar a desenvolver el dict ["clima"] !.

if let dict = json as? [String: AnyObject] { println(dict) if let weatherDictionary = dict["weather"]! as? [AnyObject] { println("/nWeather dictionary:/n/n/(weatherDictionary)") if let descriptionString = weatherDictionary[0]["description"]! as? String { println("/nDescription of the weather is: /(descriptionString)") } } }

Tenga en cuenta que deberíamos verificar dos veces la existencia del primer Opcional.

if let dict = json as? [String: 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") } } }


Esto funciona bien para mí en el patio de recreo y en la terminal usando env xcrun swift

ACTUALIZADO PARA SWIFT 4 Y CODABLE

Aquí hay un ejemplo de Swift 4 que usa el protocolo codificable.

var jsonStr = "{/"weather/":[{/"id/":804,/"main/":/"Clouds/",/"description/":/"overcast clouds/",/"icon/":/"04d/"}],}" struct Weather: Codable { let id: Int let main: String let description: String let icon: String } struct Result: Codable { let weather: [Weather] } do { let weather = try JSONDecoder().decode(Result.self, from: jsonStr.data(using: .utf8)!) print(weather) } catch { print(error) }

ACTUALIZADO PARA SWIFT 3.0

He actualizado el código para Swift 3 y también se muestra cómo ajustar el JSON analizado en objetos. ¡Gracias por todos los votos!

import Foundation struct Weather { let id: Int let main: String let description: String let icon: String } extension Weather { init?(json: [String: Any]) { guard let id = json["id"] as? Int, let main = json["main"] as? String, let description = json["description"] as? String, let icon = json["icon"] as? String 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: String.Encoding.ascii, allowLossyConversion: false) do { var json = try JSONSerialization.jsonObject(with: data!, options: []) guard let dict = json as? [String: Any] else { throw JSONParseError.notADictionary } guard let weatherJSON = dict["weather"] as? [[String: Any]] else { throw JSONParseError.missingWeatherObjects } let weather = weatherJSON.flatMap(Weather.init) print(weather) } catch { print(error) }

- Respuesta anterior -

import Foundation var jsonStr = "{/"weather/":[{/"id/":804,/"main/":/"Clouds/",/"description/":/"overcast clouds/",/"icon/":/"04d/"}],}" var data = jsonStr.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: false) var localError: NSError? var json: AnyObject! = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: &localError) if let dict = json as? [String: 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) } } }

Como aún estoy recibiendo votos para esta respuesta, pensé que volvería a visitarla para Swift 2.0:

import Foundation var jsonStr = "{/"weather/":[{/"id/":804,/"main/":/"Clouds/",/"description/":/"overcast clouds/",/"icon/":/"04d/"}],}" var data = jsonStr.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: false) do { var json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) if let dict = json as? [String: AnyObject] { if let weather = dict["weather"] as? [AnyObject] { for dict2 in weather { let id = dict2["id"] as? Int let main = dict2["main"] as? String let description = dict2["description"] as? String print(id) print(main) print(description) } } } } catch { print(error) }

La mayor diferencia es que la variable json ya no es un tipo opcional y la sintaxis do / try / catch. También seguí y escribí el id , el main y la description .


Tratar:

Con eso puedes ir así:

let obj:[String:AnyObject] = [ "array": [JSON.null, false, 0, "", [], [:]], "object":[ "null": JSON.null, "bool": true, "int": 42, "double": 3.141592653589793, "string": "a α/t弾/n𪚲", "array": [], "object": [:] ], "url":"http://blog.livedoor.com/dankogai/" ] let json = JSON(obj) json.toString() json["object"]["null"].asNull // NSNull() json["object"]["bool"].asBool // true json["object"]["int"].asInt // 42 json["object"]["double"].asDouble // 3.141592653589793 json["object"]["string"].asString // "a α/t弾/n𪚲" json["array"][0].asNull // NSNull() json["array"][1].asBool // false json["array"][2].asInt // 0 json["array"][3].asString // ""


Usando mi biblioteca ( https://github.com/isair/JSONHelper ) puede hacer esto con su variable json de tipo 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 [String: AnyObject] weathers <-- jsonDictionary["weather"] }

Si su matriz no hubiera estado bajo la clave "clima", su código habría sido solo esto:

var weathers = [Weather]() weathers <-- json

O si tiene una cadena json en sus manos, también puede pasarla, en lugar de crear primero un diccionario JSON a partir de la cadena. La única configuración que debe hacer es escribir una clase o estructura de clima:

struct Weather: Deserializable { var id: String? var name: String? var description: String? var icon: String? init(data: [String: AnyObject]) { id <-- data["id"] name <-- data["name"] description <-- data["description"] icon <-- data["icon"] } }