I'm calling an api in swift 3. And from the api I'm getting response in JSON String format. How to convert that JSON String to Dictionary or Array in Swift. Also that JSON string contains further array's and dictionaries.
I've tried using EVReflection tool. It's only converting the upper JSON object in dictionary. The nested dictionaries and array's are still in String format.
Try something like this, response is [String: Any] so you must cast to a any type
DispatchQueue.main.async {
do {
if let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any] {
let j = json as NSDictionary
guard let resp = response as? HTTPURLResponse
else {
// No response from server
return
}
if resp.statusCode == 200 {
// You can put here some callback, this is a data you need
} else {
// Here is some error
}
}
} catch {
// And this is a error from server
}
}
You should receive jsonData which you can directly try JSONSerialization.
If for any reason you receive it as json String then you have to convert that string to jsonData first
// Here you have to convert Json String to jsonData
// if it's not Json String then skip this line
let jsonData = jsonString.data(using: .utf8)
// Try to convert it to json object
do {
let json = try JSONSerialization.jsonObject(with: jsonData, options: []) as! [String : Any]
// now you can try to parse your json
} catch let error as NSError {
print(error.localizedDescription)
}
Or as #Jay mentioned use Swiftyjson
Related
I use alamofire for requests. Here on a simple response, I'm getting this JSON string from alamofire
Optional("[{\"nl2br\":\"2019-05-02 19:52:10\",\"nl3br\":\"\",\"nl4br\":\"#lxr\",\"nl5br\":\"1\",\"nl6br\":\"nein\",\"nl7br\":\"bARxrdw9c7WS1RN9c\\/\\/MrA==822b5dd20cb73611:35cab43d0c7e82e73c62818d9f90cfe8\",\"nl8br\":\"tBDSzkQ7eCNERwldgZiwKg==a7590d9d8affdbe5:63b9a9bf6421ea7db2a55f8773990b08\",\"nl9br\":\"fpd17pxVUzcJWNskVWyBeA==cf21783de8334248:a93e8b8a92ef9b238b75ad87a315ce3e\"},{\"nl2br\":\"2019-04-26 21:36:32\",\"nl3br\":\"old\",\"nl4br\":\"\",\"nl5br\":null,\"nl6br\":\"ja\",\"nl7br\":\"emjUIzK92fWwHNLv\\/4xv2Q==8fca202c9a816c7b:655ef8aaaa0212bb9e77a9c35a56c3a7\",\"nl8br\":\"1C5Hy\\/ZhMk3b6SZY8c08lw==cb3b0f4fdd6b5957:034e72d400598fedc43b3111d841a31b\",\"nl9br\":\"KUfLHbih9612dhNCYPOrTg==48da9c3362430e01:3a80ba9fb516e4172aa39b017abcd96e\"},{\"nl2br\":\"2019-04-26 21:20:24\",\"nl3br\":\"holder\",\"nl4br\":\"\",\"nl5br\":null,\"nl6br\":\"ja\",\"nl7br\":\"J59nMBWUMyU9PzdbwQqd0g==f7d3c6c561c33f0b:3465e9131a2577c39cddcc606d0785b0\",\"nl8br\":\"G4rRevk951ZBJJQKzBeJZg==45c0ebcdc1e000e8:dc770c3849fef8b058f85cad42c73e1d\",\"nl9br\":\"338Ud9CIDgnyBV96F2Fx\\/w==d0f825064e0ecf81:0ca00ff27e977ef5f8123d38c643a8b3\"},{\"nl2br\":\"2019-04-10 23:57:17\",\"nl3br\":\"\",\"nl4br\":\"Wasmes, here\'s a video and do ya need?\",\"nl5br\":\"1\",\"nl6br\":\"ja\",\"nl7br\":\"fw17O1L9SuO9FS3qu6U7QQ==706bd09ee3b5ec55:6667d9020a0edcacbd217f631d2305c0\",\"nl8br\":\"2tTE9+0Kr6cVSuEOsq8h0w==3e0e46352da323be:941710bd881546dfa08d3afb6aea2831\",\"nl9br\":\"NAkMx0OsKwXVGndYXbAFmA==1234c0b2992502bf:666f8efd3bdf8ee8b0a2ee4e7222c2ef\"},{\"nl2br\":\"2019-02-22 21:38:16\",\"nl3br\":\"i\'m giving up on you, but don\'t \",\"nl4br\":\"\",\"nl5br\":null,\"nl6br\":\"nein\",\"nl7br\":\"gOv13Dsxf1N2UG46KT3tvQ==dd02a83b1837bb24:4f7c7ab95e873d35685ab7b738626f44\",\"nl8br\":\"40+GOpcNU6M4F688DJyxFA==70bc177842f3f6cf:232b065423bd2683d75ca177775fd352\",\"nl9br\":\"mBc3pEHKBiiPeAEpZRskug==71b353fed6403b99:c58099676beacc146c14867645e29783\"}]")
I get my data like this and convert it like this
if let responseData = response.data {
let responseDataString = String(data: responseData, encoding:String.Encoding(rawValue: String.Encoding.utf8.rawValue))
print(responseDataString) // gives the whole string above
if let obj = responseDataString?.toJSON() as? [String:AnyObject] {
print(obj["nl2br"] as! String) // gives nothing, just nil
}
}
My string extension is like this.
extension String {
func toJSON() -> Any? {
guard let data = self.data(using: .utf8, allowLossyConversion: false) else { return nil }
return try? JSONSerialization.jsonObject(with: data, options: .mutableContainers)
}
}
Any idea why this behaviour is expected? I tried printing obj that gives nothing too.
Your root is an array not a dictionary Change responseDataString?.toJSON() as? [[String:Any]]
extension String {
func toJSON() -> Any? {
return try? JSONSerialization.jsonObject(with: Data(self.utf8))
}
}
let responseDataString:String? = """[{\"nl2br\":\"2019-05-02 19:52:10\",\"nl3br\":\"\",\"nl4br\":\"#lxr\",\"nl5br\":\"1\",\"nl6br\":\"nein\",\"nl7br\":\"bARxrdw9c7WS1RN9c\\/\\/MrA==822b5dd20cb73611:35cab43d0c7e82e73c62818d9f90cfe8\",\"nl8br\":\"tBDSzkQ7eCNERwldgZiwKg==a7590d9d8affdbe5:63b9a9bf6421ea7db2a55f8773990b08\",\"nl9br\":\"fpd17pxVUzcJWNskVWyBeA==cf21783de8334248:a93e8b8a92ef9b238b75ad87a315ce3e\"},{\"nl2br\":\"2019-04-26 21:36:32\",\"nl3br\":\"old\",\"nl4br\":\"\",\"nl5br\":null,\"nl6br\":\"ja\",\"nl7br\":\"emjUIzK92fWwHNLv\\/4xv2Q==8fca202c9a816c7b:655ef8aaaa0212bb9e77a9c35a56c3a7\",\"nl8br\":\"1C5Hy\\/ZhMk3b6SZY8c08lw==cb3b0f4fdd6b5957:034e72d400598fedc43b3111d841a31b\",\"nl9br\":\"KUfLHbih9612dhNCYPOrTg==48da9c3362430e01:3a80ba9fb516e4172aa39b017abcd96e\"},{\"nl2br\":\"2019-04-26 21:20:24\",\"nl3br\":\"holder\",\"nl4br\":\"\",\"nl5br\":null,\"nl6br\":\"ja\",\"nl7br\":\"J59nMBWUMyU9PzdbwQqd0g==f7d3c6c561c33f0b:3465e9131a2577c39cddcc606d0785b0\",\"nl8br\":\"G4rRevk951ZBJJQKzBeJZg==45c0ebcdc1e000e8:dc770c3849fef8b058f85cad42c73e1d\",\"nl9br\":\"338Ud9CIDgnyBV96F2Fx\\/w==d0f825064e0ecf81:0ca00ff27e977ef5f8123d38c643a8b3\"},{\"nl2br\":\"2019-04-10 23:57:17\",\"nl3br\":\"\",\"nl4br\":\"Wasmes, here\'s a video and do ya need?\",\"nl5br\":\"1\",\"nl6br\":\"ja\",\"nl7br\":\"fw17O1L9SuO9FS3qu6U7QQ==706bd09ee3b5ec55:6667d9020a0edcacbd217f631d2305c0\",\"nl8br\":\"2tTE9+0Kr6cVSuEOsq8h0w==3e0e46352da323be:941710bd881546dfa08d3afb6aea2831\",\"nl9br\":\"NAkMx0OsKwXVGndYXbAFmA==1234c0b2992502bf:666f8efd3bdf8ee8b0a2ee4e7222c2ef\"},{\"nl2br\":\"2019-02-22 21:38:16\",\"nl3br\":\"i\'m giving up on you, but don\'t \",\"nl4br\":\"\",\"nl5br\":null,\"nl6br\":\"nein\",\"nl7br\":\"gOv13Dsxf1N2UG46KT3tvQ==dd02a83b1837bb24:4f7c7ab95e873d35685ab7b738626f44\",\"nl8br\":\"40+GOpcNU6M4F688DJyxFA==70bc177842f3f6cf:232b065423bd2683d75ca177775fd352\",\"nl9br\":\"mBc3pEHKBiiPeAEpZRskug==71b353fed6403b99:c58099676beacc146c14867645e29783\"}]"""
if let obj = responseDataString?.toJSON() as? [[String:Any]] {
obj.forEach {
print($0["nl2br"])
}
}
Result
Optional(2019-05-02 19:52:10)
Optional(2019-04-26 21:36:32)
Optional(2019-04-26 21:20:24)
Optional(2019-04-10 23:57:17)
Optional(2019-02-22 21:38:16)
Edit: In json this
[{
"name":"ppp"
}]
is an array of dictionaries to be [[String:Any]] notice nested [[]] , while this
{
"name":"ppp"
}
is a dictionary represented by [String:Any] notice only []
After decrypting my response from API i am getting a string "name:DM100, profile:[1,2,4,5]".
How can i convert this to a json object where name is string and profile is an array
i have tried using but getting nil
if let data = testString.data(using: .utf8) {
do {
return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
} catch {
print("JSON Serialization Error :-> \(error.localizedDescription)")
}
}
return nil
}
Your JSON String is not valid. It should look like this:
let testString = "{\"name\":\"DM100\", \"profile\":[1,2,4,5]}"
if let data = testString.data(using: .utf8) {
do {
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
print(json["name"])
}
}
catch {
print(error.localizedDescription)
}
}
Start and end with curly braces {} and have double quotations around string keys and values.
You can use following code to get the output:
But String must have and valid JSON format first as follows:
let string = "{\"name\":\"DM100\", \"profile\":[1,2,4,5]}"
let data = string.data(using: .utf8)!
do {
if let jsonObj = try JSONSerialization.jsonObject(with: data, options : .allowFragments) as? Dictionary<String,Any> {
print(jsonObj)
} else {
print("JSON Error")
}
} catch let error as NSError {
print(error)
}
I'm attempting to cast a JSON response in swift to a useable dictionary. This seemed like a simple task, however the JSON response I am getting is formatted strangely, and no matter what I try, I am unable to cast it to a dictionary. All of the google examples I've been able to find assume that the format of the JSON response will be as follows:
{
"someKey": 42.0,
"anotherKey": {
"someNestedKey": true
},
{
"someKey": 42.0,
"anotherKey": {
"someNestedKey": true
}
However, the print response in swift I'm receiving using the code below is formatted as follows:
{assets = (
{
"someKey": 42.0,
"anotherKey": {
"someNestedKey": true
},
{
"someKey": 42.0,
"anotherKey": {
"someNestedKey": true
}
);
}
Here is as far as I was able to get in attempting to cast this data to a dictionary in swift. It adds "assets" as the single key in the dictionary, with the value of that key being the entire rest of the response.
let url = URL(string: "https://\(apiKey):\(password)#\(yourStore).myshopify.com/admin/themes/\(currentThemeID)/assets.json")!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error)
} else {
if let urlContent = data {
do {
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: [.allowFragments, JSONSerialization.ReadingOptions.mutableContainers])
print(jsonResult)
if let dictionary = jsonResult as? [String: [String]] {
print(dictionary)
}
} catch {
print("json processing failed")
}
}
}
}
task.resume()
I'm pretty sure the hang up resides around the presence of the two "parenthesis" and "semi-colon" in the JSON response. I'm unable to find any documentation on how those characters effect the response, or on how to handle them when attempting to down-cast in swift.
Any help would be appreciated!
EDIT:
I've pulled up the JSON response in my browser, and here is the formatting:
{"assets":[{"key":"assets\/1-1.png","public_url":"https:\/\/cdn.shopify.com\/s\/files\/1\/0810\/2125\/t\/22\/assets\/1-1.png?5272098227851596200","created_at":"2016-05-16T16:58:27-05:00","updated_at":"2016-05-16T16:58:27-05:00","content_type":"image\/png","size":9127,"theme_id":124078279}{"key":"templates\/search.liquid","public_url":null,"created_at":"2016-05-16T16:59:04-05:00","updated_at":"2016-05-16T16:59:04-05:00","content_type":"text\/x-liquid","size":2931,"theme_id":124078279}]}
This JSON response does not have the assets = (); portion in it, and is formatted correctly. Somehow my swift code is improperly parsing the data?
Repeatedly cast as [String: Any] to get down to the part of the JSON response you want.
do {
let jsonResult = try JSONSerialization.jsonObject(with: urlContent, options: [.allowFragments, JSONSerialization.ReadingOptions.mutableContainers])
print(jsonResult)
guard
let dictionary = jsonResult as? [String: Any],
let assetData = dictionary["assets"] as? [String: Any] else {
print("The JSON structure doesn't meet our expectations \(urlContent)")
return
}
print(assetData)
} catch {
print("json processing failed")
}
I try to deseralize my JSON that look like this :
{
"access_token": "This_is_my_token"
"item01": "blabla"
"item02": "blabla"
...
}
and I want to save only access_token into a variable. Not a big deal.
For exemple, with PHP it is something really simple like:
<?php
$jsonObj = json_decode($jsonString);
$access_token = $jsonObj["access_token"];
?>
But it doesn't look this easy with Swift. I try many things but nothing works for me.
Here is the code I have:
dataString = String(data: data, encoding: .utf8)!
do {
let anyObj: AnyObject? = try JSONSerialization.jsonObject(with: dataString, options: JSONSerialization.ReadingOptions([])) as AnyObject
guard let access_token = anyObj?.firstItem as? [String: AnyObject]
else {return}
print(access_token)
} catch {
print("JSON Deserial. Error")
}
with this code, I can't manipulate anyObj like I do with $jsonObj in PHP, there is no way to do something like anyObj["access_token"]
How can I access to this item in the object ?
Thanks
You can simply call this function by passing your data here and it will return a dictionary. From that dictionary you can pick access_token value.
class func parseJsonToDictionary(data: Data) -> ([String:AnyObject]?,Error?) {
let _ = NSString(data: data, encoding:String.Encoding.utf8.rawValue)
do {
let JSONObject = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
return (JSONObject as? [String:AnyObject],nil)
} catch let error as NSError {
return (nil,error)
}
}
If you are having json string and not json data then you can use this method to convert it to dictionary.
func convertToDictionary(text: String) -> [String: Any]? {
if let data = text.data(using: .utf8) {
do {
return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
} catch {
print(error.localizedDescription)
}
}
return nil
}
let str = "{\"name\":\"James\"}"
let dict = convertToDictionary(text: str)
Later you can get value of access_token from dictionary.
Instead of casting anyObj to AnyObject try casting it to a dictionary of strings like
let anyObj: AnyObject? = try JSONSerialization.jsonObject(with: dataString, options: JSONSerialization.ReadingOptions([])) as [String:String]
Then you can get accessToken by using anyObj["access_token"]
Im trying to run to serialize the JSON response, but I am getting an error on the "let json = ..." line. The error is "Ambiguous reference to member 'jsonObject(with:options:)'". If anyone knows how to fix this I will apprechiate it
Alamofire.request("https://httpbin.org/get").responseJSON { response in
if let JSON = response.result.value {
do {
let json = try JSONSerialization.jsonObject(with: response.result.value!, options: .allowFragments)
} catch {
print ()
}
print("JSON: \(JSON)")
}
}
Because response.result.value is type of a dictionary __NSDictionaryI, not a Data as jsonObject expected. You can retrieve value from JSON with ease, no need to convert to json, for example: JSON["title"]