Convertir diccionario a JSON en Swift

188

He creado el siguiente diccionario:

var postJSON = [ids[0]:answersArray[0], ids[1]:answersArray[1], ids[2]:answersArray[2]] as Dictionary

y obtengo:

[2: B, 1: A, 3: C]

Entonces, ¿cómo puedo convertirlo a JSON?

Orkhan Alizade
fuente
1
NSJSONSerialization
Matthias Bauch

Respuestas:

240

Swift 3.0

Con Swift 3, el nombre NSJSONSerializationy sus métodos han cambiado, de acuerdo con las Pautas de diseño de API de Swift .

let dic = ["2": "B", "1": "A", "3": "C"]

do {
    let jsonData = try JSONSerialization.data(withJSONObject: dic, options: .prettyPrinted)
    // here "jsonData" is the dictionary encoded in JSON data

    let decoded = try JSONSerialization.jsonObject(with: jsonData, options: [])
    // here "decoded" is of type `Any`, decoded from JSON data

    // you can now cast it with the right type        
    if let dictFromJSON = decoded as? [String:String] {
        // use dictFromJSON
    }
} catch {
    print(error.localizedDescription)
}

Swift 2.x

do {
    let jsonData = try NSJSONSerialization.dataWithJSONObject(dic, options: NSJSONWritingOptions.PrettyPrinted)
    // here "jsonData" is the dictionary encoded in JSON data

    let decoded = try NSJSONSerialization.JSONObjectWithData(jsonData, options: [])
    // here "decoded" is of type `AnyObject`, decoded from JSON data

    // you can now cast it with the right type 
    if let dictFromJSON = decoded as? [String:String] {
        // use dictFromJSON
    }
} catch let error as NSError {
    print(error)
}

Swift 1

var error: NSError?
if let jsonData = NSJSONSerialization.dataWithJSONObject(dic, options: NSJSONWritingOptions.PrettyPrinted, error: &error) {
    if error != nil {
        println(error)
    } else {
        // here "jsonData" is the dictionary encoded in JSON data
    }
}

if let decoded = NSJSONSerialization.JSONObjectWithData(jsonData, options: nil, error: &error) as? [String:String] {
    if error != nil {
        println(error)
    } else {
        // here "decoded" is the dictionary decoded from JSON data
    }
}

Eric Aya
fuente
Me sale el siguiente [2: A, 1: A, 3: A]. ¿Pero qué hay de las llaves?
Orkhan Alizade
1
No entiendo tu pregunta. ¿Qué corchetes? Preguntaste sobre codificar un diccionario en JSON, y esa es mi respuesta.
Eric Aya
1
JSON llaves, como{"result":[{"body":"Question 3"}] }
Orkhan Alizade
2
@OrkhanAlizade La llamada anterior para dataWithJSONObject que producir las "llaves" (es decir, los frenos) como parte de la resultante NSDataobjeto.
Rob
Gracias. nota al margen: considere usar d0 en su lugar para abreviar (diccionario).
johndpope
166

Estás haciendo una suposición equivocada. El hecho de que el depurador / Playground muestre su diccionario entre corchetes (así es como Cocoa muestra los diccionarios) no significa que esa sea la forma en que se formatea la salida JSON.

Aquí hay un código de ejemplo que convertirá un diccionario de cadenas a JSON:

Versión Swift 3:

import Foundation

let dictionary = ["aKey": "aValue", "anotherKey": "anotherValue"]
if let theJSONData = try? JSONSerialization.data(
    withJSONObject: dictionary,
    options: []) {
    let theJSONText = String(data: theJSONData,
                               encoding: .ascii)
    print("JSON string = \(theJSONText!)")
}

Para mostrar lo anterior en formato "bastante impreso", debe cambiar la línea de opciones a:

    options: [.prettyPrinted]

O en la sintaxis de Swift 2:

import Foundation
 
let dictionary = ["aKey": "aValue", "anotherKey": "anotherValue"]
let theJSONData = NSJSONSerialization.dataWithJSONObject(
  dictionary ,
  options: NSJSONWritingOptions(0),
  error: nil)
let theJSONText = NSString(data: theJSONData!,
  encoding: NSASCIIStringEncoding)
println("JSON string = \(theJSONText!)")

La salida de eso es

"JSON string = {"anotherKey":"anotherValue","aKey":"aValue"}"

O en formato bonito:

{
  "anotherKey" : "anotherValue",
  "aKey" : "aValue"
}

El diccionario está encerrado entre llaves en la salida JSON, tal como cabría esperar.

EDITAR:

En la sintaxis Swift 3/4, el código anterior se ve así:

  let dictionary = ["aKey": "aValue", "anotherKey": "anotherValue"]
    if let theJSONData = try?  JSONSerialization.data(
      withJSONObject: dictionary,
      options: .prettyPrinted
      ),
      let theJSONText = String(data: theJSONData,
                               encoding: String.Encoding.ascii) {
          print("JSON string = \n\(theJSONText)")
    }
  }
Duncan C
fuente
Una cadena Swift normal también funciona en la declaración JSONText.
Fred Faust el
@thefredelement, ¿cómo se convierte NSData directamente en una cadena Swift? La conversión de datos a cadenas es una función de NSString.
Duncan C
Estaba implementando este método y utilicé el inicio de datos / codificación en una cadena Swift, no estoy seguro de si estaba disponible en Swift 1.x.
Fred Faust
Me salvó el día Gracias.
Shobhit C
debe seleccionarse la respuesta (y)
iBug
50

Swift 5:

let dic = ["2": "B", "1": "A", "3": "C"]
let encoder = JSONEncoder()
if let jsonData = try? encoder.encode(dic) {
    if let jsonString = String(data: jsonData, encoding: .utf8) {
        print(jsonString)
    }
}

Tenga en cuenta que las claves y los valores deben implementarse Codable. Cadenas, Ints y Dobles (y más) ya están Codable. Consulte Codificación y decodificación de tipos personalizados .

Ryan H
fuente
26

Mi respuesta a tu pregunta está abajo

let dict = ["0": "ArrayObjectOne", "1": "ArrayObjecttwo", "2": "ArrayObjectThree"]

var error : NSError?

let jsonData = try! NSJSONSerialization.dataWithJSONObject(dict, options: NSJSONWritingOptions.PrettyPrinted)

let jsonString = NSString(data: jsonData, encoding: NSUTF8StringEncoding)! as String

print(jsonString)

La respuesta es

{
  "0" : "ArrayObjectOne",
  "1" : "ArrayObjecttwo",
  "2" : "ArrayObjectThree"
}
usuario3182143
fuente
24

A veces es necesario imprimir la respuesta del servidor con fines de depuración. Aquí hay una función que uso:

extension Dictionary {

    var json: String {
        let invalidJson = "Not a valid JSON"
        do {
            let jsonData = try JSONSerialization.data(withJSONObject: self, options: .prettyPrinted)
            return String(bytes: jsonData, encoding: String.Encoding.utf8) ?? invalidJson
        } catch {
            return invalidJson
        }
    }

    func printJson() {
        print(json)
    }

}

Ejemplo de uso:

(lldb) po dictionary.printJson()
{
  "InviteId" : 2,
  "EventId" : 13591,
  "Messages" : [
    {
      "SenderUserId" : 9514,
      "MessageText" : "test",
      "RecipientUserId" : 9470
    },
    {
      "SenderUserId" : 9514,
      "MessageText" : "test",
      "RecipientUserId" : 9470
    }
  ],
  "TargetUserId" : 9470,
  "InvitedUsers" : [
    9470
  ],
  "InvitingUserId" : 9514,
  "WillGo" : true,
  "DateCreated" : "2016-08-24 14:01:08 +00:00"
}
Andrey Gordeev
fuente
24

DictionaryExtensión Swift 4 .

extension Dictionary {
    var jsonStringRepresentation: String? {
        guard let theJSONData = try? JSONSerialization.data(withJSONObject: self,
                                                            options: [.prettyPrinted]) else {
            return nil
        }

        return String(data: theJSONData, encoding: .ascii)
    }
}
thexande
fuente
Esta es una forma buena y reutilizable de resolver el problema, pero una pequeña explicación ayudaría a los recién llegados a comprenderlo mejor.
nilobarp
¿Podría aplicarse esto si las claves del diccionario contienen una matriz de objetos personalizados?
Raju yourPepe
2
No es buena idea usarlo encoding: .asciien extensión pública. .utf8será mucho más seguro!
ArtFeel
esto imprime con caracteres de escape ¿hay algún lugar para evitar eso?
MikeG
10

Swift 3 :

let jsonData = try? JSONSerialization.data(withJSONObject: dict, options: [])
let jsonString = String(data: jsonData!, encoding: .utf8)!
print(jsonString)
Bilal
fuente
Esto se bloqueará si alguna parte es nula, muy mala práctica para forzar el desenvolvimiento de los resultados. // De todos modos, ya hay la misma información (sin el bloqueo) en otras respuestas, evite publicar contenido duplicado. Gracias.
Eric Aya
5

La respuesta a su pregunta está a continuación:

Swift 2.1

     do {
          if let postData : NSData = try NSJSONSerialization.dataWithJSONObject(dictDataToBeConverted, options: NSJSONWritingOptions.PrettyPrinted){

          let json = NSString(data: postData, encoding: NSUTF8StringEncoding)! as String
          print(json)}

        }
        catch {
           print(error)
        }
Dheeraj D
fuente
2

Aquí hay una extensión fácil para hacer esto:

https://gist.github.com/stevenojo/0cb8afcba721838b8dcb115b846727c3

extension Dictionary {
    func jsonString() -> NSString? {
        let jsonData = try? JSONSerialization.data(withJSONObject: self, options: [])
        guard jsonData != nil else {return nil}
        let jsonString = String(data: jsonData!, encoding: .utf8)
        guard jsonString != nil else {return nil}
        return jsonString! as NSString
    }

}
StevenOjo
fuente
1
private func convertDictToJson(dict : NSDictionary) -> NSDictionary?
{
    var jsonDict : NSDictionary!

    do {
        let jsonData = try JSONSerialization.data(withJSONObject:dict, options:[])
        let jsonDataString = String(data: jsonData, encoding: String.Encoding.utf8)!
        print("Post Request Params : \(jsonDataString)")
        jsonDict = [ParameterKey : jsonDataString]
        return jsonDict
    } catch {
        print("JSON serialization failed:  \(error)")
        jsonDict = nil
    }
    return jsonDict
}
Swati Desai
fuente
1
Varios errores aquí. ¿Por qué usar NSDictionary de Foundation en lugar de Swift's Dictionary? Además, ¿por qué devolver un nuevo diccionario con una Cadena como valor, en lugar de devolver los datos JSON reales? Esto no tiene sentido. Además, el opcional envuelto implícitamente devuelto como opcional realmente no es una buena idea en absoluto.
Eric Aya