48

I need to create JSON like this:

Order = {   type_id:'1',model_id:'1',

   transfer:{
     startDate:'10/04/2015 12:45',
     endDate:'10/04/2015 16:00',
     startPoint:'Ул. Момышулы, 45',
     endPoint:'Аэропорт Астаны'
   },
   hourly:{
     startDate:'10/04/2015',
     endDate:'11/04/2015',
     startPoint:'ЖД Вокзал',
     endPoint:'',
     undefined_time:'1'
   },
   custom:{
     startDate:'12/04/2015',
     endDate:'12/04/2015',
     startPoint:'Астана',
     endPoint:'Павлодар',
     customPrice:'50 000'
   },
    commentText:'',
    device_type:'ios'
};

The problem is that I can not create valid JSON. Here is how I create object:

let jsonObject: [AnyObject]  = [
        ["type_id": singleStructDataOfCar.typeID, "model_id": singleStructDataOfCar.modelID, "transfer": savedDataTransfer, "hourly": savedDataHourly, "custom": savedDataReis, "device_type":"ios"]
    ]

where savedData are dictionaries:

let savedData: NSDictionary = ["ServiceDataStartDate": singleStructdata.startofWork, 
"ServiceDataAddressOfReq": singleStructdata.addressOfRequest, 
"ServiceDataAddressOfDel": singleStructdata.addressOfDelivery, 
"ServiceDataDetailedText": singleStructdata.detailedText, "ServiceDataPrice": singleStructdata.priceProposed]

When I use only strings creating my JSON object everything works fine. However when I include dictionaries NSJSONSerialization.isValidJSONObject(value) returns false. How can I create a valid dictionary?

7
  • Try to follow this tutorial medium.com/swift-programming/4-json-in-swift-144bf5f88ce4 Commented Apr 8, 2015 at 11:08
  • Yes, red that article. That article nsdictionary only has string values. In my case var transfer, hourly, custom have many values. it is not string ... so how should I include them ? Commented Apr 8, 2015 at 11:16
  • let jsonObject: [AnyObject] = [ ["type_id": singleStructDataOfCar.typeID, "model_id": singleStructDataOfCar.modelID, "transfer":[ "startDate":savedDataTransfer["ServiceDataStartDate"] as String, "EndPoint": savedDataTransfer["ServiceDataAddressOfDel"] as String, "CommentText": savedDataTransfer["ServiceDataDetailedText"] as String, "StartPoint":savedDataTransfer["ServiceDataAddressOfReq"] as String ] ]//, "hourly": savedDataHourly, "custom": savedDataReis, "device_type":"ios"] ] Commented Apr 8, 2015 at 11:18
  • I know this is messy code. but it also doesnt work Commented Apr 8, 2015 at 11:18
  • 2
    I guess indeed one of the singleStructdata.* items is not json convertible. Try each of these individually with NSJSONSerialization.isValidJSONObject and you'll find your culprit. Commented Apr 8, 2015 at 11:21

8 Answers 8

81

One problem is that this code is not of type Dictionary.

let jsonObject: [Any]  = [
    [
         "type_id": singleStructDataOfCar.typeID,
         "model_id": singleStructDataOfCar.modelID, 
         "transfer": savedDataTransfer, 
         "hourly": savedDataHourly, 
         "custom": savedDataReis, 
         "device_type":"iOS"
    ]
]

The above is an Array of AnyObject with a Dictionary of type [String: AnyObject] inside of it.

Try something like this to match the JSON you provided above:

let savedData = ["Something": 1]

let jsonObject: [String: Any] = [ 
    "type_id": 1,
    "model_id": 1,
    "transfer": [
        "startDate": "10/04/2015 12:45",
        "endDate": "10/04/2015 16:00"
    ],
    "custom": savedData
]

let valid = JSONSerialization.isValidJSONObject(jsonObject) // true
Sign up to request clarification or add additional context in comments.

8 Comments

This is correct, but I want to give a shout to SwiftyJSON pod for whoever comes next. It can be useful.
SwiftyJSON has a great implementation for this. This current answer is not valid, but, after installing SwiftyJSON, just change [String: AnyObject to JSON and it IS valid. Later on when you are trying to get the value as a Dictionary, just type jsonData.dictionaryObject and there you have it!
I've changed [String: AnyObject] to be [String: Any] so that the example code compiles. I originally used AnyObject in the above so that the jsonObject could have class instances inside of it.
why is jsonObject["transfer"]["startDate"] giving me error?
Here is the error: error: type 'Any?' has no subscript members jsonObject["transfer"]["startDate"] The key "transfer" gives you an Any? (optional Any); this is per the type given to jsonObject, which is [String: Any] (keys of type String, values of type Any).
|
35

For Swift 3.0, as of December 2016, this is how it worked for me:

let jsonObject: NSMutableDictionary = NSMutableDictionary()

jsonObject.setValue(value1, forKey: "b")
jsonObject.setValue(value2, forKey: "p")
jsonObject.setValue(value3, forKey: "o")
jsonObject.setValue(value4, forKey: "s")
jsonObject.setValue(value5, forKey: "r")

let jsonData: NSData

do {
    jsonData = try JSONSerialization.data(withJSONObject: jsonObject, options: JSONSerialization.WritingOptions()) as NSData
    let jsonString = NSString(data: jsonData as Data, encoding: String.Encoding.utf8.rawValue) as! String
    print("json string = \(jsonString)")                                    

} catch _ {
    print ("JSON Failure")
}

EDIT 2018: I now use SwiftyJSON library to save time and make my development life easier and better. Dealing with JSON natively in Swift is an unnecessary headache and pain, plus wastes too much time, and creates code which is hard to read and write, and hence prone to lots of errors.

Comments

12

Creating a JSON String:

let para:NSMutableDictionary = NSMutableDictionary()
para.setValue("bidder", forKey: "username")
para.setValue("day303", forKey: "password")
para.setValue("authetication", forKey: "action")
let jsonData = try! NSJSONSerialization.dataWithJSONObject(para, options: NSJSONWritingOptions.allZeros)
let jsonString = NSString(data: jsonData, encoding: NSUTF8StringEncoding) as! String
print(jsonString)

Comments

7

• Swift 4.1, April 2018

Here is a more general approach that can be used to create a JSON string by using values from a dictionary:

struct JSONStringEncoder {
    /**
     Encodes a dictionary into a JSON string.
     - parameter dictionary: Dictionary to use to encode JSON string.
     - returns: A JSON string. `nil`, when encoding failed.
     */
    func encode(_ dictionary: [String: Any]) -> String? {
        guard JSONSerialization.isValidJSONObject(dictionary) else {
            assertionFailure("Invalid json object received.")
            return nil
        }

        let jsonObject: NSMutableDictionary = NSMutableDictionary()
        let jsonData: Data

        dictionary.forEach { (arg) in
            jsonObject.setValue(arg.value, forKey: arg.key)
        }

        do {
            jsonData = try JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted)
        } catch {
            assertionFailure("JSON data creation failed with error: \(error).")
            return nil
        }

        guard let jsonString = String.init(data: jsonData, encoding: String.Encoding.utf8) else {
            assertionFailure("JSON string creation failed.")
            return nil
        }

        print("JSON string: \(jsonString)")
        return jsonString
    }
}

How to use it:

let exampleDict: [String: Any] = [
        "Key1" : "stringValue",         // type: String
        "Key2" : boolValue,             // type: Bool
        "Key3" : intValue,              // type: Int
        "Key4" : customTypeInstance,    // type: e.g. struct Person: Codable {...}
        "Key5" : customClassInstance,   // type: e.g. class Human: NSObject, NSCoding {...}
        // ... 
    ]

    if let jsonString = JSONStringEncoder().encode(exampleDict) {
        // Successfully created JSON string.
        // ... 
    } else {
        // Failed creating JSON string.
        // ...
    }

Note: If you are adding instances of your custom types (structs) into the dictionary make sure your types conform to the Codable protocol and if you are adding objects of your custom classes into the dictionary make sure your classes inherit from NSObject and conform to the NSCoding protocol.

5 Comments

also if you describe how to use, the user who see can understand easy.
@HardikThakkar It's quite straight forward. I've edited the answer with How to use snippet.
@Baran Emre how would you decode deocde jsonString into a [String:Any] dict?
@BaranEmre just to add to add to last question, the json I'm encoding have arbitrarily valued keys of type String. Think userIds generated by some service.
@chibro2 You want to create a Dictionary from a JSON String, right? If yes, then do the following: let data: Data! = yourString.data(using: .utf8) and then let dictionary = try! JSONSerialization.jsonObject(with: data, options: []) as! [String: Any].
5

Swift 5 - 6/30/21

Adopt the Codable protocol (similar to interface in other programming languages)

struct ConfigRequestBody: Codable {
var systemid: String
var password: String
var request: String = "getconfig"

init(systemID: String, password: String){
    self.systemid = systemID
    self.password = password
 }
}

Create instance of struct/class that you want to turn into JSON:

let requestBody = ConfigRequestBody(systemID: systemID, password: password)

Encode the object into JSON using a JSONEncoder. Here I print the string representation so you can see the result:

    let encoder = JSONEncoder()
    encoder.outputFormatting = .prettyPrinted
    do {
        let result = try encoder.encode(requestBody)
        // RESULT IS NOW JSON-LIKE DATA OBJECT
        if let jsonString = String(data: result, encoding: .utf8){
            // JSON STRING
            print("JSON \(jsonString)")
        }
    } catch {
        print("Your parsing sucks \(error)")
        return nil
    }
}

1 Comment

In 2022, THIS needs to be the accepted answer -- far easier than what was necessary in older versions of Swift!
4

This worked for me... Swift 2

static func checkUsernameAndPassword(username: String, password: String) -> String?{
    let para:NSMutableDictionary = NSMutableDictionary()
        para.setValue("demo", forKey: "username")
        para.setValue("demo", forKey: "password")
       // let jsonError: NSError?
    let jsonData: NSData
    do{
        jsonData = try NSJSONSerialization.dataWithJSONObject(para, options: NSJSONWritingOptions())
        let jsonString = NSString(data: jsonData, encoding: NSUTF8StringEncoding) as! String
        print("json string = \(jsonString)")
        return jsonString

    } catch _ {
        print ("UH OOO")
        return nil
    }
}

Comments

3

Check out https://github.com/peheje/JsonSerializerSwift

Use case:

//Arrange your model classes
class Object {
  var id: Int = 182371823
  }
class Animal: Object {
  var weight: Double = 2.5
  var age: Int = 2
  var name: String? = "An animal"
  }
class Cat: Animal {
  var fur: Bool = true
}

let m = Cat()

//Act
let json = JSONSerializer.toJson(m)

//Assert
let expected = "{\"fur\": true, \"weight\": 2.5, \"age\": 2, \"name\": \"An animal\", \"id\": 182371823}"
stringCompareHelper(json, expected) //returns true

Currently supports standard types, optional standard types, arrays, arrays of nullables standard types, array of custom classes, inheritance, composition of custom objects.

3 Comments

i have a json which has one property which itself is an array of a custom object. When running through JsonSerialization.toJson, this loses the values and I am getting something like: "key": [{},{}] any thoughts on how to get around this?
It works with array of custom objects check the GitHub test file for an example of how to do this. The test case is called test_arrayOfCustomClass_included
I switched my struct to a class and it worked. Any support for structs as custom objects?
-1

Use SwiftyJSON to generate JSON string. Learn from the comments of the answer of Matt.

@2022/10

let savedData = ["Something": 1]

var json = JSON()

json.dictionaryObject = [ 
    "type_id": 1,
    "model_id": 1,
    "transfer": [
        "startDate": "10/04/2015 12:45",
        "endDate": "10/04/2015 16:00"
    ],
    "custom": savedData
]

let jsonStr = json.rawString()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.