257

I have create the next Dictionary:

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

and I get:

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

So, how can I convert it to JSON?

nhgrif
  • 61,578
  • 25
  • 134
  • 173
Orkhan Alizade
  • 7,379
  • 14
  • 40
  • 79
  • 1
    [`NSJSONSerialization`](https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSJSONSerialization_Class/index.html) – Matthias Bauch Apr 14 '15 at 10:48
  • Or [`JSONEncoder`](https://developer.apple.com/documentation/foundation/jsonencoder) with [custom types](https://developer.apple.com/documentation/foundation/archives_and_serialization/using_json_with_custom_types). See [Encoding and Decoding Custom Types](https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types). – Rob Jul 09 '23 at 16:52

16 Answers16

311

Swift 3.0

With Swift 3, the name of NSJSONSerialization and its methods have changed, according to the Swift API Design Guidelines.

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
  • 69,473
  • 35
  • 181
  • 253
210

You are making a wrong assumption. Just because the debugger/Playground shows your dictionary in square brackets (which is how Cocoa displays dictionaries) that does not mean that is the way the JSON output is formatted.

Here is example code that will convert a dictionary of strings to JSON:

Swift 3 version:

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

To display the above in "pretty printed" format you'd change the options line to:

    options: [.prettyPrinted]

Or in Swift 2 syntax:

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

The output of that is

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

Or in pretty format:

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

The dictionary is enclosed in curly braces in the JSON output, just as you'd expect.

EDIT:

In Swift 3/4 syntax, the code above looks like this:

  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)")
    }
  }
Community
  • 1
  • 1
Duncan C
  • 128,072
  • 22
  • 173
  • 272
  • A regular Swift string works as well on theJSONText declaration. – Fred Faust Jan 13 '16 at 19:58
  • @thefredelement, How do you convert NSData directly to a Swift string though? The data to string conversion is a function of NSString. – Duncan C Jan 14 '16 at 15:09
  • I was implementing this method and used the data / encoding init on a Swift string, I'm not sure if that was available on Swift 1.x. – Fred Faust Jan 14 '16 at 15:14
  • Neither your description of your problem nor your code make much sense. – VyTcdc May 30 '18 at 12:55
  • @VyTcdc My code in the answer? Or was this intended for the OP? – Duncan C May 30 '18 at 13:09
  • this is changing sequence of keys how to prevent sequence while converting string to json? – Pooja M. Bohora Mar 22 '19 at 05:48
  • @PoojaM.Bohora I am not sure what you are trying to ask, and adding a comment to an answer that's almost a year old is not a good idea. Post a new question. – Duncan C Mar 22 '19 at 11:59
  • why to post a new question if I am getting solution in same question answer and having only doubt in it – Pooja M. Bohora Mar 22 '19 at 12:01
  • Because (1) that is how you are supposed to ask questions on SO. You don't have a "doubt". You are asking a new question in a comment to an answer. – Duncan C Mar 22 '19 at 12:14
  • (2) your question is incoherent. I think I understand what you are trying to ask but it is not a grammatical sentence. Create a question with sample data, the result you expect, and what you get instead. – Duncan C Mar 22 '19 at 12:15
89

Swift 5:

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

Note that keys and values must implement Codable. Strings, Ints, and Doubles (and more) are already Codable. See Encoding and Decoding Custom Types.

Also note that Any does not conform to Codable. It is likely still a good approach to adapt your data to become Codable so that you are making use of Swift typing (especially in the case that you are also going to decode any encoded json), and so that you can be more declarative about the outcome of your encoding.

Ryan H
  • 1,656
  • 14
  • 15
  • 17
    Just for the future reference, this solution won't work if your dict is of type [String, Any] – nja Aug 20 '20 at 10:52
  • 1
    Agreed, but for the sake of future readers, it should be noted that `[String: Any]` is a bit of an anti-pattern, nowadays. Generally we would use [custom types](https://developer.apple.com/documentation/foundation/archives_and_serialization/using_json_with_custom_types) rather than `[String: Any]`. That offers better strongly-typed code with better compile-time validation. And we’d then encode it with `JSONEncoder`. Sometimes (with legacy code, especially that which integrates with Objective-C) we have to use `JSONSerialization`, but `JSONEncoder` is definitely the preferred solution nowadays. – Rob Jul 09 '23 at 16:45
37

My answer for your question is below

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: String.Encoding.utf8.rawValue)! as String

print(jsonString)

Answer is

{
  "0" : "ArrayObjectOne",
  "1" : "ArrayObjecttwo",
  "2" : "ArrayObjectThree"
}
Miguel Ruivo
  • 16,035
  • 7
  • 57
  • 87
user3182143
  • 9,459
  • 3
  • 32
  • 39
32

Swift 4 Dictionary extension.

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

        return String(data: theJSONData, encoding: .ascii)
    }
}
TofuBeer
  • 60,850
  • 18
  • 118
  • 163
thexande
  • 1,645
  • 16
  • 23
29

Sometimes it's necessary to print out server's response for debugging purposes. Here's a function I use:

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

}

Example of use:

(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
  • 30,606
  • 13
  • 135
  • 162
15

Swift 5:

extension Dictionary {
    
    /// Convert Dictionary to JSON string
    /// - Throws: exception if dictionary cannot be converted to JSON data or when data cannot be converted to UTF8 string
    /// - Returns: JSON string
    func toJson() throws -> String {
        let data = try JSONSerialization.data(withJSONObject: self)
        if let string = String(data: data, encoding: .utf8) {
            return string
        }
        throw NSError(domain: "Dictionary", code: 1, userInfo: ["message": "Data cannot be converted to .utf8 string"])
    }
}
Alexander Volkov
  • 7,904
  • 1
  • 47
  • 44
12

Swift 3:

let jsonData = try? JSONSerialization.data(withJSONObject: dict, options: [])
let jsonString = String(data: jsonData!, encoding: .utf8)!
print(jsonString)
Bilal
  • 197
  • 2
  • 8
  • 1
    This will crash if any part is nil, very bad practice to force unwrap the results. // Anyway there's already the same information (without the crash) in other answers, please avoid posting duplicate content. Thanks. – Eric Aya Oct 02 '17 at 08:35
6

In Swift 5.4

extension Dictionary {
    var jsonData: Data? {
        return try? JSONSerialization.data(withJSONObject: self, options: [.prettyPrinted])
    }
    
    func toJSONString() -> String? {
        if let jsonData = jsonData {
            let jsonString = String(data: jsonData, encoding: .utf8)
            return jsonString
        }
        
        return nil
    }
}

The idea of having it as a variable is because then you can reuse it like that:

extension Dictionary {
    func decode<T:Codable>() throws -> T {
        return try JSONDecoder().decode(T.self, from: jsonData ?? Data())
    }
}
Reimond Hill
  • 4,278
  • 40
  • 52
5

Answer for your question is below:

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
  • 4,386
  • 4
  • 20
  • 34
2

Here's an easy extension to do this:

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
  • 2,498
  • 1
  • 16
  • 21
1

using lldb

(lldb) p JSONSerialization.data(withJSONObject: notification.request.content.userInfo, options: [])
(Data) $R16 = 375 bytes
(lldb) p String(data: $R16!, encoding: .utf8)!
(String) $R18 = "{\"aps\": \"some_text\"}"

//or
p String(data: JSONSerialization.data(withJSONObject: notification.request.content.userInfo, options: [])!, encoding: .utf8)!
(String) $R4 = "{\"aps\": \"some_text\"}"
yoAlex5
  • 29,217
  • 8
  • 193
  • 205
1
 do{
        let dataDict = [ "level" :
                            [
                                ["column" : 0,"down" : 0,"left" : 0,"right" : 0,"row" : 0,"up" : 0],
                                ["column" : 1,"down" : 0,"left" : 0,"right" : 0,"row" : 0,"up" : 0],
                                ["column" : 2,"down" : 0,"left" : 0,"right" : 0,"row" : 0,"up" : 0],
                                ["column" : 0,"down" : 0,"left" : 0,"right" : 0,"row" : 1,"up" : 0],
                                ["column" : 1,"down" : 0,"left" : 0,"right" : 0,"row" : 1,"up" : 0],
                                ["column" : 2,"down" : 0,"left" : 0,"right" : 0,"row" : 1,"up" : 0]
                            ]
        ]
        var jsonData = try JSONSerialization.data(withJSONObject: dataDict, options: JSONSerialization.WritingOptions.prettyPrinted)
        let jsonStringData =  NSString(data: jsonData as Data, encoding: NSUTF8StringEncoding)! as String
        print(jsonStringData)
    }catch{
        print(error.localizedDescription)
    }
Mujahed Ansari
  • 419
  • 4
  • 13
0

This works for me:

import SwiftyJSON

extension JSON {
    
    mutating func appendIfKeyValuePair(key: String, value: Any){
        if var dict = self.dictionaryObject {
            dict[key] = value
            self = JSON(dict)
        }
    }
}

Usage:

var data: JSON = []

data.appendIfKeyValuePair(key: "myKey", value: "myValue")
GIJoeCodes
  • 1,680
  • 1
  • 25
  • 28
0

2022, swift 5

usage of extensions:

Encode:

if let json = statisticsDict.asJSONStr() {
     //your action with json
}

Decode from Dictionary:

json.decodeFromJson(type: [String:AppStat].self)
    .onSuccess{
        $0// your dictionary of type: [String:AppStat]
    }

extensions:

@available(macOS 10.15, *)
public extension Encodable {
    func asJson() -> Result<String, Error>{
        JSONEncoder()
            .try(self)
            .flatMap{ $0.asString() }
    }
}

public extension String {
    func decodeFromJson<T>(type: T.Type) -> Result<T, Error> where T: Decodable {
        self.asData()
            .flatMap { JSONDecoder().try(type, from: $0) }
    }
}

///////////////////////////////
/// HELPERS
//////////////////////////////

@available(macOS 10.15, *)
fileprivate extension JSONEncoder {
    func `try`<T : Encodable>(_ value: T) -> Result<Output, Error> {
        do {
            return .success(try self.encode(value))
        } catch {
            return .failure(error)
        }
    }
}

fileprivate extension JSONDecoder {
    func `try`<T: Decodable>(_ t: T.Type, from data: Data) -> Result<T,Error> {
        do {
            return .success(try self.decode(t, from: data))
        } catch {
            return .failure(error)
        }
    }
}

fileprivate extension String {
    func asData() -> Result<Data, Error> {
        if let data = self.data(using: .utf8) {
            return .success(data)
        } else {
            return .failure(WTF("can't convert string to data: \(self)"))
        }
    }
}

fileprivate extension Data {
    func asString() -> Result<String, Error> {
        if let str = String(data: self, encoding: .utf8) {
            return .success(str)
        } else {
            return .failure(WTF("can't convert Data to string"))
        }
    }
}

fileprivate func WTF(_ msg: String, code: Int = 0) -> Error {
    NSError(code: code, message: msg)
}

internal extension NSError {
    convenience init(code: Int, message: String) {
        let userInfo: [String: String] = [NSLocalizedDescriptionKey:message]
        self.init(domain: "FTW", code: code, userInfo: userInfo)
    }
}
Andrew_STOP_RU_WAR_IN_UA
  • 9,318
  • 5
  • 65
  • 101
-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
}
  • 1
    Several mistakes here. Why using Foundation's NSDictionary instead of Swift's Dictionary?! Also why returning a new dictionary with a String as value, instead of returning the actual JSON data? This doesn't make sense. Also the implicitly unwrapped optional returned as an optional is really not a good idea at all. – Eric Aya Dec 13 '18 at 09:23