Buscar..


Sintaxis

  • NSJSONSerialization.JSONObjectWithData (jsonData, opciones: NSJSONReadingOptions) // Devuelve un objeto de jsonData. Este método arroja en el fracaso.
  • NSJSONSerialization.dataWithJSONObject (jsonObject, opciones: NSJSONWritingOptions) // Devuelve NSData de un objeto JSON. Pase en NSJSONWritingOptions.PrettyPrinted en opciones para una salida que sea más legible.

Serialización, codificación y decodificación JSON con Apple Foundation y Swift Standard Library

La clase JSONSerialization está integrada en el marco de la Fundación de Apple.

2.2

Leer json

La función JSONObjectWithData toma NSData y devuelve AnyObject . Se puede usar as? para convertir el resultado a su tipo esperado.

do {
    guard let jsonData = "[\"Hello\", \"JSON\"]".dataUsingEncoding(NSUTF8StringEncoding) else {
        fatalError("couldn't encode string as UTF-8")
    }

    // Convert JSON from NSData to AnyObject
    let jsonObject = try NSJSONSerialization.JSONObjectWithData(jsonData, options: [])
    
    // Try to convert AnyObject to array of strings
    if let stringArray = jsonObject as? [String] {
        print("Got array of strings: \(stringArray.joinWithSeparator(", "))")
    }
} catch {
    print("error reading JSON: \(error)")
}

Puede pasar las options: .AllowFragments que se options: .AllowFragments lugar de las options: [] para permitir la lectura de JSON cuando el objeto de nivel superior no es una matriz o diccionario.

Escribir json

Al llamar a dataWithJSONObject convierte un objeto compatible con JSON (matrices anidadas o diccionarios con cadenas, números y NSNull ) en NSData bruto codificados como UTF-8.

do {
    // Convert object to JSON as NSData
    let jsonData = try NSJSONSerialization.dataWithJSONObject(jsonObject, options: [])
    print("JSON data: \(jsonData)")
    
    // Convert NSData to String
    let jsonString = String(data: jsonData, encoding: NSUTF8StringEncoding)!
    print("JSON string: \(jsonString)")
} catch {
    print("error writing JSON: \(error)")
}

Puede pasar las options: .PrettyPrinted lugar de las options: [] para impresión bonita.

3.0

Mismo comportamiento en Swift 3 pero con una sintaxis diferente.

do {
    guard let jsonData = "[\"Hello\", \"JSON\"]".data(using: String.Encoding.utf8) else {
        fatalError("couldn't encode string as UTF-8")
    }
    
    // Convert JSON from NSData to AnyObject
    let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options: [])
    
    // Try to convert AnyObject to array of strings
    if let stringArray = jsonObject as? [String] {
        print("Got array of strings: \(stringArray.joined(separator: ", "))")
    }
} catch {
    print("error reading JSON: \(error)")
}

do {
    // Convert object to JSON as NSData
    let jsonData = try JSONSerialization.data(withJSONObject: jsonObject, options: [])
    print("JSON data: \(jsonData)")

    // Convert NSData to String
    let jsonString = String(data: jsonData, encoding: .utf8)!
    print("JSON string: \(jsonString)")
} catch {
    print("error writing JSON: \(error)")
}

Nota: Lo siguiente está disponible actualmente solo en Swift 4.0 y versiones posteriores.

A partir de Swift 4.0, la biblioteca estándar Swift incluye los protocolos Encodable y Decodable para definir un enfoque estandarizado para la codificación de datos y la decodificación. La adopción de estos protocolos permitirá que las implementaciones de los protocolos de Encoder y Decoder tomen sus datos y los codifiquen o descodifiquen hacia y desde una representación externa como JSON. La conformidad con la Codable protocolo combina tanto la Encodable y Decodable protocolos. Este es ahora el medio recomendado para manejar JSON en su programa.

Codificar y decodificar automáticamente

La forma más fácil de hacer un tipo codificable es declarar sus propiedades como tipos que ya son Codable . Estos tipos incluyen tipos de biblioteca estándar como String , Int y Double ; y tipos de fundaciones, como Date , Data y URL . Si las propiedades de un tipo son codificables, el tipo en sí se ajustará automáticamente a Codable simplemente declarando la conformidad.

Considere el siguiente ejemplo, en el que la estructura del Book se ajusta a Codable .

struct Book: Codable {
    let title: String
    let authors: [String]
    let publicationDate: Date
}

Tenga en cuenta que las colecciones estándar como Array y Dictionary ajustan a Codable si contienen tipos codificables.

Al adoptar Codable , la estructura del Book ahora se puede codificar y descodificar desde JSON utilizando las clases JSONEncoder y JSONDecoder Apple Foundation, aunque Book no contiene ningún código para manejar específicamente JSON. Los codificadores y decodificadores personalizados también pueden escribirse, de conformidad con los protocolos Encoder y Decoder , respectivamente.

Codificar a datos JSON

// Create an instance of Book called book
let encoder = JSONEncoder()
let data = try! encoder.encode(book) // Do not use try! in production code
print(data)

Configure encoder.outputFormatting = .prettyPrinted para una lectura más fácil. ## Decodificar a partir de datos JSON

Decodificar a partir de datos JSON

// Retrieve JSON string from some source
let jsonData = jsonString.data(encoding: .utf8)!
let decoder = JSONDecoder()
let book = try! decoder.decode(Book.self, for: jsonData) // Do not use try! in production code
print(book)

En el ejemplo anterior, Book.self informa al decodificador del tipo al que se debe decodificar el JSON.

Codificación o decodificación exclusiva

A veces es posible que no necesite que los datos sean codificables y decodificables, como cuando solo necesita leer datos JSON de una API, o si su programa solo envía datos JSON a una API.

Si solo desea escribir datos JSON, ajuste su tipo a Encodable .

struct Book: Encodable {
    let title: String
    let authors: [String]
    let publicationDate: Date
}

Si solo desea leer datos JSON, ajuste su tipo a Decodable .

struct Book: Decodable {
    let title: String
    let authors: [String]
    let publicationDate: Date
}

Usando Nombres Clave Personalizados

Las API utilizan con frecuencia convenciones de nomenclatura distintas de la caja de camello estándar de Swift, como la caja de serpiente. Esto puede convertirse en un problema cuando se trata de decodificar JSON, ya que, de forma predeterminada, las claves JSON deben alinearse exactamente con los nombres de propiedad de su tipo. Para manejar estos escenarios, puede crear claves personalizadas para su tipo usando el protocolo CodingKey .

struct Book: Codable {
    // ...
    enum CodingKeys: String, CodingKey { 
        case title
        case authors
        case publicationDate = "publication_date"
    }
}

CodingKeys se generan automáticamente para los tipos que adoptan el protocolo Codable , pero al crear nuestra propia implementación en el ejemplo anterior, permitimos que nuestro decodificador Codable coincidir la fecha de publicationDate caso de camello local con la fecha de publication_date caso de serpiente como lo entrega la API.

SwiftyJSON

SwiftyJSON es un marco Swift creado para eliminar la necesidad de un encadenamiento opcional en la serialización JSON normal.

Puede descargarlo aquí: https://github.com/SwiftyJSON/SwiftyJSON

Sin SwiftyJSON, su código se vería así para encontrar el nombre del primer libro en un objeto JSON:

if let jsonObject = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments) as? [[String: AnyObject]],
let bookName = (jsonObject[0]["book"] as? [String: AnyObject])?["name"] as? String {
    //We can now use the book name
}

En SwiftyJSON, esto se simplifica enormemente:

let json = JSON(data: data)
if let bookName = json[0]["book"]["name"].string {
    //We can now use the book name
}

Elimina la necesidad de verificar todos los campos, ya que devolverá cero si alguno de ellos no es válido.

Para usar SwiftyJSON, descargue la versión correcta desde el repositorio de Git. Hay una rama para Swift 3. Simplemente arrastre el "SwiftyJSON.swift" a su proyecto e importe a su clase:

import SwiftyJSON

Puedes crear tu objeto JSON usando los siguientes dos inicializadores:

let jsonObject = JSON(data: dataObject)

o

let jsonObject = JSON(jsonObject) //This could be a string in a JSON format for example

Para acceder a sus datos, utilice subíndices:

let firstObjectInAnArray = jsonObject[0]
let nameOfFirstObject = jsonObject[0]["name"]

Luego, puede analizar su valor a un determinado tipo de datos, que devolverá un valor opcional:

let nameOfFirstObject = jsonObject[0]["name"].string //This will return the name as a string

let nameOfFirstObject = jsonObject[0]["name"].double //This will return null

También puede compilar sus rutas en una matriz rápida:

let convolutedPath = jsonObject[0]["name"][2]["lastName"]["firstLetter"].string

Es lo mismo que:

let convolutedPath = jsonObject[0, "name", 2, "lastName", "firstLetter"].string

SwiftyJSON también tiene funcionalidad para imprimir sus propios errores:

if let name = json[1337].string {
    //You can use the value - it is valid
} else {
    print(json[1337].error) // "Array[1337] is out of bounds" - You cant use the value
}

Si necesita escribir en su objeto JSON, puede usar subíndices de nuevo:

var originalJSON:JSON = ["name": "Jack", "age": 18]
originalJSON["age"] = 25 //This changes the age to 25
originalJSON["surname"] = "Smith" //This creates a new field called "surname" and adds the value to it

Si necesita la cadena original para el JSON, por ejemplo, si necesita escribirla en un archivo, puede obtener el valor en bruto:

if let string = json.rawString() { //This is a String object
    //Write the string to a file if you like
}

if let data = json.rawData() { //This is an NSData object
    //Send the data to your server if you like
}

Freddy

Freddy es una biblioteca de análisis JSON mantenida por Big Nerd Ranch . Tiene tres ventajas principales:

  1. Escriba seguridad: lo ayuda a trabajar con el envío y la recepción de JSON de forma que se eviten bloqueos en el tiempo de ejecución.

  2. Idiomatic: aprovecha los genéricos, las enumeraciones y las funciones funcionales de Swift, sin documentación complicada ni operadores mágicos personalizados.

  3. Manejo de errores: proporciona información de errores informativa para errores JSON comunes.

Ejemplo de datos JSON

Definamos algunos ejemplos de datos JSON para usar con estos ejemplos.

{
  "success": true,
  "people": [
    {
      "name": "Matt Mathias",
      "age": 32,
      "spouse": true
    },
    {
      "name": "Sergeant Pepper",
      "age": 25,
      "spouse": false
    }
  ],
  "jobs": [
    "teacher",
    "judge"
  ],
  "states": {
    "Georgia": [
      30301,
      30302,
      30303
    ],
    "Wisconsin": [
      53000,
      53001
    ]
  }
}
let jsonString = "{\"success\": true, \"people\": [{\"name\": \"Matt Mathias\",\"age\": 32,\"spouse\": true},{\"name\": \"Sergeant Pepper\",\"age\": 25,\"spouse\": false}],\"jobs\": [\"teacher\",\"judge\"],\"states\": {\"Georgia\": [30301,30302,30303],\"Wisconsin\": [53000,53001]}}"
let jsonData = jsonString.dataUsingEncoding(NSUTF8StringEncoding)!

Deserialización de datos sin procesar

Para deserializar los datos, inicializamos un objeto JSON luego accedemos a una clave particular.

do {
    let json = try JSON(data: jsonData)
    let success = try json.bool("success")
} catch {
    // do something with the error
}

Nosotros try aquí porque el acceso a la json para la tecla de "success" podría fallar - que podría no existe, o el valor para no ser un valor lógico.

También podemos especificar una ruta para acceder a los elementos anidados en la estructura JSON. La ruta es una lista de claves e índices separados por comas que describen la ruta a un valor de interés.

do {
    let json = try JSON(data: jsonData)
    let georgiaZipCodes = try json.array("states", "Georgia")
    let firstPersonName = try json.string("people", 0, "name")
} catch {
    // do something with the error
}

Deserializando modelos directamente

JSON se puede analizar directamente a una clase modelo que implementa el protocolo JSONDecodable .

public struct Person {
    public let name: String
    public let age: Int
    public let spouse: Bool
}

extension Person: JSONDecodable {
    public init(json: JSON) throws {
        name = try json.string("name")
        age = try json.int("age")
        spouse = try json.bool("spouse")
    }
}

do {
    let json = try JSON(data: jsonData)
    let people = try json.arrayOf("people", type: Person.self)
} catch {
    // do something with the error
}

Serialización de datos en bruto

Cualquier valor JSON puede ser serializado directamente a NSData .

let success = JSON.Bool(false)
let data: NSData = try success.serialize()

Serialización de modelos directamente

Cualquier clase de modelo que implemente el protocolo JSONEncodable se puede serializar directamente a NSData .

extension Person: JSONEncodable {
    public func toJSON() -> JSON {
        return .Dictionary([
            "name": .String(name),
            "age": .Int(age),
            "spouse": .Bool(spouse)
        ])
    }
}

let newPerson = Person(name: "Glenn", age: 23, spouse: true)
let data: NSData = try newPerson.toJSON().serialize()

Flecha

Arrow es una elegante biblioteca de análisis JSON en Swift.

Permite analizar JSON y asignarlo a clases de modelos personalizados con la ayuda de un operador <-- :

identifier <-- json["id"]
name <-- json["name"]
stats <-- json["stats"]

Ejemplo:

Modelo swift

struct Profile {
    var identifier = 0
    var name = ""
    var link: NSURL?
    var weekday: WeekDay = .Monday
    var stats = Stats()
    var phoneNumbers = [PhoneNumber]()
}

Archivo JSON

{
    "id": 15678,
    "name": "John Doe",
    "link": "https://apple.com/steve",
    "weekdayInt" : 3,
    "stats": {
        "numberOfFriends": 163,
        "numberOfFans": 10987
    },
    "phoneNumbers": [{
                     "label": "house",
                     "number": "9809876545"
                     }, {
                     "label": "cell",
                     "number": "0908070656"
                     }, {
                     "label": "work",
                     "number": "0916570656"
    }]
}

Cartografía

extension Profile: ArrowParsable {
    mutating func deserialize(json: JSON) {
        identifier <-- json["id"]
        link <-- json["link"]
        name <-- json["name"]
        weekday <-- json["weekdayInt"]
        stats <- json["stats"]
        phoneNumbers <-- json["phoneNumbers"]
    }
}

Uso

let profile = Profile()
profile.deserialize(json)

Instalación:

Cartago

github "s4cha/Arrow"

CocoaPods

pod 'Arrow'
use_frameworks!

A mano

Simplemente copie y pegue Arrow.swift en su proyecto Xcode

https://github.com/s4cha/Arrow

Como un marco

Descargue Arrow desde el repositorio de GitHub y genere el objetivo de Framework en el proyecto de ejemplo. Entonces enlace contra este marco.

JSON simple de análisis en objetos personalizados

Incluso si las bibliotecas de terceros son buenas, los protocolos proporcionan una forma sencilla de analizar JSON. Puedes imaginar que tienes un objeto Todo como

struct Todo {
    let comment: String
}

Cada vez que reciba el JSON, puede manejar el NSData simple como se muestra en el otro ejemplo utilizando el objeto NSJSONSerialization .

Después de eso, usando un protocolo simple JSONDecodable

typealias JSONDictionary = [String:AnyObject]
protocol JSONDecodable {
    associatedtype Element
    static func from(json json: JSONDictionary) -> Element?
}

Y hacer que tu estructura de Todo ajuste a JSONDecodable hace el truco

extension Todo: JSONDecodable {
    static func from(json json: JSONDictionary) -> Todo? {
        guard let comment = json["comment"] as? String else { return nil }
        return Todo(comment: comment)
    }
}

Puedes probarlo con este código json:

{
    "todos": [
        {
            "comment" : "The todo comment"
        }
    ]
}

Cuando lo obtuvo de la API, puede serializarlo como los ejemplos anteriores que se muestran en una instancia de AnyObject . Después de eso, puedes verificar si la instancia es una instancia de JSONDictionary

guard let jsonDictionary = dictionary as? JSONDictionary else { return }

La otra cosa a verificar, específica para este caso porque tiene una matriz de Todo en el JSON, es el diccionario todos

guard let todosDictionary = jsonDictionary["todos"] as? [JSONDictionary] else { return }

Ahora que tiene la matriz de diccionarios, puede convertir cada uno de ellos en un objeto Todo utilizando flatMap (eliminará automáticamente los valores nil de la matriz)

let todos: [Todo] = todosDictionary.flatMap { Todo.from(json: $0) }

JSON analizando Swift 3

Aquí está el archivo JSON que animals.json llamado animals.json

{
    "Sea Animals": [
    {
     "name": "Fish",
     "question": "How many species of fish are there?"    },
                {
                "name": "Sharks",
                "question": "How long do sharks live?"
                },
                {
                "name": "Squid",
                "question": "Do squids have brains?"
                },
                {
                "name": "Octopus",
                "question": "How big do octopus get?"
                },
                {
                "name": "Star Fish",
                "question": "How long do star fish live?"
                }
                ],
    "mammals": [
                {
      "name": "Dog",
      "question": "How long do dogs live?"
    },
    {
      "name": "Elephant",
      "question": "How much do baby elephants weigh?"
    },
    {
      "name": "Cats",
      "question": "Do cats really have 9 lives?"
    },
    {
      "name": "Tigers",
      "question": "Where do tigers live?"
    },
    {
      "name": "Pandas",
      "question": "WHat do pandas eat?"
    }   ] }

Importa tu archivo JSON a tu proyecto

Puede realizar esta sencilla función para imprimir su archivo JSON

   func jsonParsingMethod() {
        //get the file
        let filePath = Bundle.main.path(forResource: "animals", ofType: "json")
        let content = try! String(contentsOfFile: filePath!)
        
        let data: Data = content.data(using: String.Encoding.utf8)!
        let json: NSDictionary =  try! JSONSerialization.jsonObject(with: data as Data, options:.mutableContainers) as! NSDictionary
      
//Call which part of the file you'd like to pare
        if let results = json["mammals"] as? [[String: AnyObject]] {
            
            for res in results {
                //this will print out the names of the mammals from out file.
                if let rates = res["name"] as? String {
                    print(rates)
                }
           }
       }
    }

Si desea colocarlo en una vista de tabla, primero crearía un diccionario con un NSObject.

Cree un nuevo archivo swift llamado ParsingObject y cree sus variables de cadena.

Asegúrese de que el nombre de la variable sea el mismo que el archivo JSON

. Por ejemplo, en nuestro proyecto tenemos name y question por lo tanto, en nuestro nuevo archivo swift, usaremos

var name: String?
var question: String?

Inicialice el objeto NSO que hicimos de nuevo en nuestro ViewController.swift var array = ParsingObject Luego, realizaríamos el mismo método que teníamos antes con una modificación menor.

     func jsonParsingMethod() {
            //get the file
            let filePath = Bundle.main.path(forResource: "animals", ofType: "json")
            let content = try! String(contentsOfFile: filePath!)
            
            let data: Data = content.data(using: String.Encoding.utf8)!
            let json: NSDictionary =  try! JSONSerialization.jsonObject(with: data as Data, options:.mutableContainers) as! NSDictionary
            
//This time let's get Sea Animals
            let results = json["Sea Animals"] as? [[String: AnyObject]]
            
//Get all the stuff using a for-loop
            for i in 0 ..< results!.count {
                
//get the value
                let dict = results?[i]
                let resultsArray = ParsingObject()
                
//append the value to our NSObject file
                resultsArray.setValuesForKeys(dict!)
                array.append(resultsArray)
                
            }
          
        }

Luego lo mostramos en nuestra vista de tabla haciendo esto,

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return array.count
        }
        
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
//This is where our values are stored
            let object = array[indexPath.row]
            cell.textLabel?.text = object.name
            cell.detailTextLabel?.text = object.question
            return cell
        }


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow