Can not parse nested dictionary - json

I want to parse this JSON data, but I can't make it.
JSON data is like
My code is:
session.dataTask(with: request, completionHandler:{( data , response , error) -> Void in
if let data = data {
if let jsonObj = try? JSONSerialization.jsonObject(with: data , options: .allowFragments) as! Any {
print(jsonObj)
if let postdata = (jsonObj as AnyObject).value(forKey: "postdata") {
print(postdata)
//if let something = postdata["best_before"] as? NSDictionary{
// print(something)

The root object is clearly a dictionary ([String:Any]) not just something (Any) and use proper error handling and optional bindings to unwrap the optionals safely.
The value for key postdata is an array of dictionaries ([[String:Any]]). And don't use valueForKey – and by the way those silly bridge casts to AnyObject – unless you can explain why you explicitly need KVC.
.allowFragments is not needed because the root object is a collection type.
do {
if let jsonObj = try JSONSerialization.jsonObject(with: data) as? [String:Any],
let postdata = jsonObj["postdata"] as? [[String:Any]] {
for data in postdata {
for (key, value) in data {
print(key, value)
}
}
}
} catch {
print(error)
}

Related

JSON SWIFT, how to access the values

i have the following Json
USD {
"avg_12h" = "8252.96";
"avg_1h" = "8420.80";
"avg_24h" = "8253.11";
"avg_6h" = "8250.76";
rates = {
last = "8635.50";
};
"volume_btc" = "76.05988903";
}
where USD is a key found after searching in a json file, i want to access "avg_12h" value and assign it to a variable, what is the best way to do it.
import UIKit
/*URLSessionConfiguration.default
URLSessionConfiguration.ephemeral
URLSessionConfiguration.background(withIdentifier: <#T##String#>)
// create a URLSession instance
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)*/
/*create a URLSession instance*/
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
/*
The session.dataTask(with: url) method will perform a GET request to the url specified and its completion block
({ data, response, error in }) will be executed once response is received from the server.*/
let url = URL(string: "https://localbitcoins.com/bitcoinaverage/ticker-all-currencies")!
let task = session.dataTask(with: url) { data, response, error in
// ensure there is no error for this HTTP response
guard error == nil else {
print ("error: \(error!)")
return
}
// ensure there is data returned from this HTTP response
guard let content = data else {
print("No data")
return
}
/*JSONSerialization.jsonObject(with: content,
options: JSONSerialization.ReadingOptions.mutableContainers) as?
[String: Any] will parse the JSON data returned from web server into a dictionary*/
// serialise the data / NSData object into Dictionary [String : Any]
guard let json = (try? JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers)) as? [String: Any] else {
print("Not containing JSON")
return
}
let bolivares = "VES"
for (key, value) in json {
if key==bolivares {
print(value)
//ADD CODE TO ACCESS avg_12h and assign it to a value
}
}
}
// update UI using the response here
// execute the HTTP request
task.resume()
Assuming you are receiving the JSON as raw data and it hasn't been converted to an object yet, ou would want to do something like the following:
guard let jsonObject = try? JSONSerialization.jsonObject(with: data, options: []) as! [String:[String]] else { return }
let usd = jsonObject["USD"]
let avg_12h = usd["avg_12h"]
But this will only work based on some assumptions I've made about the JSON you've provided. Is there a way you can link to a paste of the full JSON file?
Create two simple structs to hold your data (I didn't add all fields here)
struct PriceInfo {
let avg12h: String
let avg1h: String
let rates: [Rate]
}
struct Rate {
let last: String
}
then after converting json you can map it to a dictionary of [String: PriceInfo] where the key is the currency code
do {
if let json = try JSONSerialization.jsonObject(with: content) as? [String: Any] {
let prices: [String: PriceInfo] = json.mapValues {
let dict = $0 as? [String: Any]
let avg12h = dict?["avg_12h"] as? String ?? ""
let avg1h = dict?["avg_1h"] as? String ?? ""
let rates = dict?["rates"] as? [String: String] ?? [:]
return PriceInfo(avg12h: avg12h, avg1h: avg1h, rates: rates.compactMap { rate in Rate(last: rate.value) } )
}
}
} catch {
print(error)
return
}
Try to use CodingKey, it will be more clearer and JSONDecoder().decode method. I assume that you use any JsonViewer

How do I get my Swift code to read a specific piece of information from the JSON file

I am trying to read the data for "Name" in a JSON file I am hosting using Swift and I seem to only be able to read the whole JSON file and not able to pick out specific data. My JSON file contains this:
[{"Email":"Admin#admin.com","Password":"password","Name":"Admin"}]
The swift code I am using is this:
override func viewDidLoad() {
super.viewDidLoad()
//to get data from external DB
let url = URL(string: "http://localhost/Projects/Test_mobileAPI/test_userInfo.php?email=Admin#admin.com")
let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil{
print("Error Occured")
}
else{
print("Okie")
if let content = data {
do{
//Array
let myJson = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
print("this part works")
print(myJson)
if let diction = myJson as? NSDictionary
{
if let name = myJson["Name"]{
print(name as Any)
}
}
}
catch{
print(error)
}
}
}
}
task.resume()
}
The output I keep getting is this:
Okie
this part works
(
{
Email = "Admin#admin.com";
Name = Admin;
Password = password;
}
)
But I do not get just the value for "Name". Can anyone help me get the value for "Name" (i.e "Admin")
Can you try
if let myJson = try JSONSerialization.jsonObject(with: content) as? [[String:Any]] {
if let first = myJson.first {
print(first["Name"])
}
}
The problem is that the JSON that you're receiving back isn't a Dictionary, it's a single element array with a dictionary in it. So when you do
if let diction = myJson as? NSDictionary
the myJson object is failing the cast to NSDictionary. If you unwrap the array first, you should then be able to reference the dictionary and pick off any keyed values you want:
if let array = myJson as? NSArray
{
if let myDict = array[0] as? NSDictionary
{
if let name = myDict ["Name"]{
print(name as Any)
}
}
}

How to guarantee valid JSON in Swift 4?

I'm trying to work with JSON data returned from a service. The JSON is, according to JSON validators, valid and is very simple:
[{"ID":"SDS-T589863","TotalRisk":0.2458,"TotalScore":641.032}]
However trying to parse it in my Swift 4 code it is mysteriously (to me at least) invalid. Here's my attempt to parse it:
// make the request
let task = session.dataTask(with: urlRequest) {
(data, response, error) in
// check for any errors
guard error == nil else {
print(error!)
return
}
// make sure we got data
guard let responseData = data else {
print("Error: did not receive data")
return
}
// this is fine:
guard let ddd = String(bytes: responseData, encoding: String.Encoding.utf8) else {
print("can't")
return
}
print(ddd) // prints [{"ID":"SDS-T589863","TotalRisk":0.2458,"TotalScore":641.032}] happily
do {
// cannot serialize
guard let risk = try JSONSerialization.jsonObject(with: responseData, options: [JSONSerialization.ReadingOptions.allowFragments])
as? [String: Any]
else {
print("error trying to convert data to JSON")
return
}
print(risk)
} catch {
print("error trying to convert data to JSON")
return
}
}
task.resume()
}
Assuming that I have no control over the JSON object or the format in which it is returned to me, is there a way to tell what is wrong with the JSON and perhaps format the response so that it can be serialized correctly?
You should cast your data to the [[String: Any]] type because you have array in response.
You are trying to cast to [String: Any], but you have an array of [String: Any] because your response enclosed in [] brackets.
Example:
let risk = try JSONSerialization.jsonObject(with: responseData, options: [JSONSerialization.ReadingOptions.allowFragments]) as? [[String: Any]]
Or if you want to get just only one [String: Any] object from response you can write:
let risk = (try JSONSerialization.jsonObject(with: responseData, options: [JSONSerialization.ReadingOptions.allowFragments]) as? [[String: Any]])?.first
Or if your object can be an array or not an array (but it sounds a little bit strange) you could try to cast to several possible types.
The response type is array of json objects so you have to cast it to [[String: Any]]. Since you are using Swift 4, you can use Decodable type which maps the model to the response.
let task = URLSession().dataTask(with: urlRequest) { (data, response, error) in
// check for any errors
guard error == nil else {
print(error!)
return
}
// make sure we got data
guard let responseData = data else {
print("Error: did not receive data")
return
}
do {
let decoder = JSONDecoder()
let riskArray = try decoder.decode([Risk].self, from: responseData)
print(riskArray)
} catch {
print("error trying to convert data to Model")
print(error.localizedDescription)
}
}
task.resume()
You can define your Model struct like
struct Risk: Decodable {
let id: String
let totalRisk: Double
let totalScore: Double
enum CodingKeys: String, CodingKey {
case id = "ID"
case totalRisk = "TotalRisk"
case totalScore = "TotalScore"
}
}
You can read more about Decodable protocol here

Error while parsing JSON in Swift, [String:Any] won't work

I'm trying to parse this JSON in Swift 3, but it crashes.
Here's the code
do{
let data1: Data = try! Data(contentsOf: NSURL(string: "https://gist.githubusercontent.com/DesWurstes/00baf946bd6d27e7e9355bd6e9969230/raw/a0de898faea8ddedb11b0db516967d0666255633/gist.json") as! URL)
let jsono = try JSONSerialization.jsonObject(with: data1, options: []) as! [String: Any]
}catch{
// catch isn't used here.
}
Here's the error I get when it crashes:
Could not cast value of type '__NSArrayI' (0x7fffe9cb9c08) to 'NSDictionary' (0x7fffe9cba158).
It crashes because not all of the elements of the array are string. (The root of the JSON is an array.)
To prevent it from crashing, changing the third line with this will be suitable:
let jsono = try JSONSerialization.jsonObject(with: data1, options: [])
But then, its type will be Any and I won't be able to parse it with
let string = jsono["something"] as! [String: Any] // Type "Any" has no subscript members
and this code won't run:
if let array = jsono as? [String: Any] {
print("test") // Doesn't print
}
While trying to fix error in the first code, I thought this code may work (Because it says can't convert Array to Dictionary):
let jsono = try JSONSerialization.jsonObject(with: data1, options: []) as! [String]
but it results...
Could not cast value of type '__NSDictionaryI' (0x7fffe9cba108) to 'NSString' (0x7fffea072f38).
Then how can I parse this JSON?
It looks like the JSON response returned from server is an array containing dictionaries of type [String: Any] so you can do:
if let array = jsono as? [[String: Any]] {
print("test") // Will print
for dictionary in array {
print(dictionary["url"] as! String)
}
}
Here you can download the playground I've written to test it out.
you have parse array response so you need to type cast json as? [[String: Any]]..
if your response is dictonary then you need to parse like json as? [String: Any]
func Callservice()
{
let jsonUrlString = "url"
guard let url = URL(string: jsonUrlString) else { return }
URLSession.shared.dataTask(with: url) { (data, response, err) in
guard let data = data else { return }
do {
let courses = try JSONDecoder().decode([Course].self, from: data)
self.arrayData = courses
print(courses)
} catch let jsonErr {
print("Error serializing json:", jsonErr)
}
}.resume()
}
struct course:decodable{
let name:string?
}

Swift JSONSerialization.jsonObject Error

I've looked around but I don't find an answer to fix this error that has been bugging me. I tried adding a "as! NSMutableArray" but that gave me another error. Any ideas on how to fix it? I converted my project from Objective-C to Swift, so hopefully the code is all good I had 20+ errors now I'm down to 3 errors. Thank you.
Error Message:
'jsonObject' produces 'Any', not the expected contextual result type 'NSMutableArray'
Code for retrieving data from server
// Retrieving Data from Server
func retrieveData() {
let getDataURL = "http://ip/example.org/json.php"
let url: NSURL = NSURL(string: getDataURL)!
do {
let data: NSData = try NSData(contentsOf: url as URL)
jsonArray = JSONSerialization.jsonObject(with: data, options: nil)
}
catch {
print("Error: (data: contentsOf: url)")
}
// Setting up dataArray
var dataArray: NSMutableArray = []
// Looping through jsonArray
for i in 0..<jsonArray.count {
// Create Data Object
let dID: String = (jsonArray[i] as AnyObject).object(forKey: "id") as! String
let dName: String = (jsonArray[i] as AnyObject).object(forKey: "dataName") as! String
let dStatus1: String = (jsonArray[i] as AnyObject).object(forKey: "dataStatus1") as! String
let dStatus2: String = (jsonArray[i] as AnyObject).object(forKey: "dataStatus2") as! String
let dURL: String = (jsonArray[i] as AnyObject).object(forKey: "dataURL") as! String
// Add Data Objects to Data Array
dataArray.add(Data(dataName: dName, andDataStatus1: dStatus1, andDataStatus2: dStatus2, andDataURL: dURL, andDataID: dID))
}
self.myTableView.reloadData()
}
The jsonObject function will return a value of type Any but the jsonArray's type of NSMutableArray. And this function will throw an error if something is wrong, put a try keyword before it. In my experience, let change the type of jsonArray to array of dictionary, so you will extract data with ease.
do {
let data: Data = try Data(contentsOf: url as URL)
let jsonArray: [[String: AnyObject]] = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! [[String: AnyObject]]
print("json: \(jsonArray)")
for dict in jsonArray {
let dataName = dict["dataName"] as! String
print("dataName: \(dataName)")
}
}
catch {
print("Error: (data: contentsOf: url)")
}