Konwertuj słownik na JSON w Swift

188

Utworzyłem następny słownik:

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

i dostaję:

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

Jak mogę go przekonwertować na JSON?

Orkhan Alizade
źródło
1
NSJSONSerialization
Matthias Bauch

Odpowiedzi:

240

Swift 3.0

W Swift 3 nazwa NSJSONSerializationi jej metody uległy zmianie, zgodnie z wytycznymi projektowymi API 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)
}

Szybki 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
źródło
Dostaję następny [2: A, 1: A, 3: A]. Ale co z nawiasami klamrowymi?
Orkhan Alizade
1
Nie rozumiem twojego pytania. Jakie nawiasy klamrowe? Zapytałeś o kodowanie słownika w JSON, i to moja odpowiedź.
Eric Aya
1
Nawiasy klamrowe JSON, takie jak{"result":[{"body":"Question 3"}] }
Orkhan Alizade
2
@OrkhanAlizade Powyższy wywołanie dataWithJSONObject będzie produkować „nawiasów klamrowych” (czyli wzmocnienia) jako część powstałego NSDataobiektu.
Rob
dzięki. uwaga dodatkowa - rozważ użycie d0 zamiast skrótu (dic).
johndpope
166

Dokonujesz błędnego założenia. Tylko dlatego, że debugger / Plac zabaw pokazuje Twój słownik w nawiasach kwadratowych (tak jak Cocoa wyświetla słowniki), co nie znaczy, że tak jest sformatowane wyjście JSON.

Oto przykładowy kod, który przekonwertuje słownik ciągów na JSON:

Wersja 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!)")
}

Aby wyświetlić powyższe w formacie „ładnie wydrukowanym”, zmień wiersz opcji na:

    options: [.prettyPrinted]

Lub w składni 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!)")

Wynikiem tego jest

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

Lub w ładnym formacie:

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

Słownik jest zamknięty w nawiasach klamrowych na wyjściu JSON, tak jak można się spodziewać.

EDYTOWAĆ:

W składni Swift 3/4 powyższy kod wygląda następująco:

  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.
źródło
Zwykły ciąg Swift działa również w deklaracji JSONText.
Fred Faust
@thefredelement, jak przekonwertować NSData bezpośrednio na ciąg Swift? Konwersja danych na ciąg jest funkcją NSString.
Duncan C
Wdrażałem tę metodę i użyłem init danych / kodowania w łańcuchu Swift, nie jestem pewien, czy był on dostępny w Swift 1.x.
Fred Faust
Uratowałem mój dzień. Dzięki.
Shobhit C
należy wybrać odpowiedź (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)
    }
}

Pamiętaj, że klucze i wartości muszą zostać zaimplementowane Codable. Strings, Ints i Doubles (i więcej) są już Codable. Zobacz Kodowanie i dekodowanie typów niestandardowych .

Ryan H.
źródło
26

Moja odpowiedź na twoje pytanie znajduje się poniżej

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)

Odpowiedź to

{
  "0" : "ArrayObjectOne",
  "1" : "ArrayObjecttwo",
  "2" : "ArrayObjectThree"
}
użytkownik3182143
źródło
24

DictionaryRozszerzenie 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
źródło
Jest to dobry i wielokrotnego użytku sposób rozwiązania problemu, ale małe wyjaśnienie pomogłoby początkującym lepiej go zrozumieć.
nilobarp
Czy można to zastosować, jeśli klucze słownika zawierają tablicę niestandardowych obiektów?
Raju yourPepe
2
Nie jest dobrym pomysłem korzystanie encoding: .asciiz rozszerzenia publicznego. .utf8będzie znacznie bezpieczniejszy!
ArtFeel,
to odciski ze znakami ucieczki czy istnieje gdziekolwiek, aby temu zapobiec?
MikeG
23

Czasami konieczne jest wydrukowanie odpowiedzi serwera do celów debugowania. Oto funkcja, której używam:

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)
    }

}

Przykład zastosowania:

(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
źródło
10

Swift 3 :

let jsonData = try? JSONSerialization.data(withJSONObject: dict, options: [])
let jsonString = String(data: jsonData!, encoding: .utf8)!
print(jsonString)
Bilal
źródło
Spowoduje to awarię, jeśli jakakolwiek część jest zerowa, bardzo zła praktyka wymuszania rozpakowywania wyników. // W każdym razie już te same informacje (bez awarii) w innych odpowiedziach, unikaj publikowania zduplikowanych treści. Dzięki.
Eric Aya,
5

Odpowiedź na twoje pytanie znajduje się poniżej:

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.
źródło
2

Oto łatwe rozszerzenie, aby to zrobić:

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
źródło
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
źródło
1
Kilka błędów tutaj. Dlaczego warto używać NSDictionary Foundation zamiast Swift's Dictionary ?! Także po co zwracać nowy słownik z wartością String jako wartość, zamiast zwracać rzeczywiste dane JSON? To nie ma sensu. Również niejawnie rozpakowana opcja opcjonalna zwrócona jako opcja nie jest wcale dobrym pomysłem.
Eric Aya,