How to convert JSON structure into dictionary or structure - json

I'm extracting exchange rates for different currencies. I have a solution that works, but it doesn't seem elegant. I use a JSON input file and I want to convert it into a dictionary so I can access easily the exchange rate for a currency for a specific day.
My goal is to have the best way to do it without too much code and flexibility.
It's in Swift 5, with a JSON input file. The input file looks like:
{
"terms":{
"url": "https://www.banqueducanada.ca/conditions-utilisation-avis/"
},
"seriesDetail":{
"FXEURCAD":{"label":"EUR/CAD","description":"Taux de change quotidien de l’euro en dollars canadiens"},
"FXGBPCAD":{"label":"GBP/CAD","description":"Taux de change quotidien de la livre sterling en dollars canadiens"},
"FXMXNCAD":{"label":"MXN/CAD","description":"Taux de change quotidien du peso mexicain en dollars canadiens"},
"FXUSDCAD":{"label":"USD/CAD","description":"Taux de change quotidien du dollar américain en dollars canadiens"}
},
"observations":[
{"d":"2019-04-29","FXUSDCAD":{"v":1.3456}, "FXEURCAD":{"v":1.5029}, "FXGBPCAD":{"v":1.7391}, "FXMXNCAD":{"v":0.07083}},
{"d":"2019-04-30","FXUSDCAD":{"v":1.3423}, "FXEURCAD":{"v":1.5055}, "FXGBPCAD":{"v":1.7493}, "FXMXNCAD":{"v":0.07071}},
{"d":"2019-05-01","FXUSDCAD":{"v":1.3416}, "FXEURCAD":{"v":1.5070}, "FXGBPCAD":{"v":1.7540}, "FXMXNCAD":{"v":0.07105}},
{"d":"2019-05-02","FXUSDCAD":{"v":1.3462}, "FXEURCAD":{"v":1.5055}, "FXGBPCAD":{"v":1.7543}, "FXMXNCAD":{"v":0.07053}},
{"d":"2019-05-03","FXUSDCAD":{"v":1.3429}, "FXEURCAD":{"v":1.5021}, "FXGBPCAD":{"v":1.7611}, "FXMXNCAD":{"v":0.07069}}
]
}
I'm extracting the "observations" section.
The list of currencies for a date can vary. It can have more or less. I have a minimum of one currency. I would like to have a solution that doesn't require that I manually code the different exchange rates.
func getCurrencies (){
var currencies = [String : [String:Double]]()
if let urlJSON = URL(string: "https://www.banqueducanada.ca/valet/observations/FXUSDCAD,FXEURCAD,FXGBPCAD,FXMXNCAD/json?recent=5"){
do {
let contents = try String(contentsOf: urlJSON)
print(contents)
let data = Data(contents.utf8)
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
let observations = json["observations"] as! [[String: Any]]
for (x,part) in observations.enumerated() {
let date = part["d"] as! String
currencies [date] = [String:Double]()
// get the currencies in the JSON structure
currencies [date]!["FXEURCAD"] = (part["FXEURCAD"] as! [String : Double])["v"]
currencies [date]!["FXGBPCAD"] = (part["FXGBPCAD"] as! [String : Double])["v"]
currencies [date]!["FXMXNCAD"] = (part["FXMXNCAD"] as! [String : Double])["v"]
currencies [date]!["FXUSDCAD"] = (part["FXUSDCAD"] as! [String : Double])["v"]
} // for
print (currencies)
} // if let json
} catch {}
} // if
} // getCurrencies
The currencies dictionary produced is fine:
["2019-05-02": ["FXGBPCAD": 1.7543, "FXMXNCAD": 0.07053, "FXEURCAD": 1.5055, "FXUSDCAD": 1.3462],
"2019-05-01": ["FXGBPCAD": 1.754, "FXEURCAD": 1.507, "FXMXNCAD": 0.07105, "FXUSDCAD": 1.3416],
"2019-05-03": ["FXEURCAD": 1.5021, "FXUSDCAD": 1.3429, "FXMXNCAD": 0.07069, "FXGBPCAD": 1.7611],
"2019-04-30": ["FXEURCAD": 1.5055, "FXMXNCAD": 0.07071, "FXUSDCAD": 1.3423, "FXGBPCAD": 1.7493],
"2019-04-29": ["FXGBPCAD": 1.7391, "FXEURCAD": 1.5029, "FXUSDCAD": 1.3456, "FXMXNCAD": 0.07083]]
I can extract a value using that command:
print (currencies ["2019-05-03"]!["FXUSDCAD"]!)
Is there a better way to do it? Is the JSONSerialization.jsonObject the right way to do it?

In this case JSONSerialization is a reasonable way however never load data synchronously from a remote URL.
This is a more generic version with a parameter for the currencies and with an asynchronous network request.
func getCurrencies(_ currencies : [String]){
var result = [String : [String:Double]]()
if let urlJSON = URL(string: "https://www.banqueducanada.ca/valet/observations/" + currencies.joined(separator:",") + "/json?recent=5"){
URLSession.shared.dataTask(with: urlJSON) { (data, _, error) in
if let error = error { print(error); return }
do {
if let json = try JSONSerialization.jsonObject(with: data!) as? [String: Any] {
let observations = json["observations"] as! [[String: Any]]
for part in observations {
let date = part["d"] as! String
result[date] = [String:Double]()
// get the currencies in the JSON structure
for currency in currencies {
result[date]![currency] = (part[currency] as! [String : Double])["v"]
}
} // for
print(result)
} // if let json
} catch {
print(error)
}
}.resume()
} // if
} // getC
getCurrencies(["FXUSDCAD","FXEURCAD","FXGBPCAD","FXMXNCAD"])

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

I need help parsing some JSON data

I am fairly new to parsing json data and I am attempting to parse some json data from an rss feed generator and I am running into a problem where I can successfully print the data I am getting but I can't save the data to an object.
I have looked through tutorials that used decodables/codables mostly but I was able to use the urlSession and jsonSerialization objects for what I needed just fine.
class JSONSongs {
// initialize song array...
var songArray: [Song] = []
func getSongs() {
let jsonSongUrl = "https://rss.itunes.apple.com/api/v1/us/apple-music/top-songs/all/50/explicit.json"
let songUrl = URL(string: jsonSongUrl) // convert string to usable url
// start url session task with apple music api url...
// we get some data(hopefully), a response code and an error(hoepfully not)
let songTask = URLSession.shared.dataTask(with: songUrl!) { (data, response, error) in
// checking for an error
if error != nil {
print(Error.self)
print(error?.localizedDescription)
return
} else {
// lets store our data in a variable
if let content = data {
do {
// taking the json data and converting it so we can make objects
let json = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers)
//print(json) // making sure data is present
// checking to see if our json data is there
guard let jsonOne = json as? [String: Any] else {
print("invalid operation!")
return
}
// accessing top root of the json file
if let feed = jsonOne["feed"] as? [String: Any] {
//print("it worked") // testing
// accessing the results array where the albums are stored
// there are arrays in the nested json data so we need the double brackets to access them
if let result = feed["results"] as? [[String: Any]]{
for item in result {
// attempting to store data in Song object, this is where problems appear
if let songName = (item["name"] as AnyObject? as? String),
let artistName = (item["artistName"] as AnyObject? as? String),
let coverArt = (item["artworkUrl100"] as AnyObject? as? String),
let artistPage = (item["artistUrl"] as AnyObject? as? String) {
self.songArray.append(Song(songName: songName, artistName: artistName, coverArt: coverArt, artistPage: artistPage))
// printing the data to the console works here but I can't save the data to an object
}
}
}
}
} catch {
print(error.localizedDescription)
print(Error.self)
return
}
}
}
}
songTask.resume()
}
}
All I get is either nil when I try and print a string value or 0 when I try and count the number of objects that are present in the songArray array
Basically your code is correct and should work, however this is a version using Decodable.
The songs property will contain the song data
struct Root : Decodable {
let feed : Feed
}
struct Feed : Decodable {
let results : [Song]
}
struct Song : Decodable {
let name, artistName : String
let artworkUrl100, artistUrl : URL
}
class JSONSongs {
var songs = [Song]()
func getSongs() {
let jsonSongUrl = "https://rss.itunes.apple.com/api/v1/us/apple-music/top-songs/all/50/explicit.json"
let songUrl = URL(string: jsonSongUrl) // convert string to usable url
// start url session task with apple music api url...
// we get some data(hopefully), a response code and an error(hoepfully not)
let songTask = URLSession.shared.dataTask(with: songUrl!) { [weak self] data, _, error in
// checking for an error
if let error = error { print(error); return }
do {
// taking the json data and converting it so we can make objects
let result = try JSONDecoder().decode(Root.self, from: data!)
self?.songs = result.feed.results
print(self?.songs)
} catch {
print(error)
}
}
songTask.resume()
}
}

Parsing json response with nested " in swift

I wanted to know the best way to parse json response of below type in Swift 4. Response is double encoded -
\"[{\\"value\\":\\"International University \\\\"MITSO\\\\"\\",\\"id\\":\\"a1v24000000uOrPAAU\\",\\"addlFields\\":[\\"Mi?narodny Universitet \\\\"MITSO\\\\"\\"]}]\"
Here is the data in NSData format -
(String) $R0 = "data: Optional(146 bytes) as NSData: <225b7b5c 2276616c 75655c22 3a5c2249 6e746572 6e617469 6f6e616c 20556e69 76657273 69747920 5c5c5c22 4d495453 4f5c5c5c 225c222c 5c226964 5c223a5c 22613176 32343030 30303030 754f7250 4141555c 222c5c22 6164646c 4669656c 64735c22 3a5b5c22 4d693f6e 61726f64 6e792055 6e697665 72736974 6574205c 5c5c224d 4954534f 5c5c5c22 5c225d7d 5d22>"
As you see value of the key "value" has a inner double quotes(").
JSONSerialization consider this as invalid Json.
Any help will be greatly appreciated.
The content of your data as String is as follows:
"[{\"value\":\"International University \\\"MITSO\\\"\",\"id\":\"a1v24000000uOrPAAU\",\"addlFields\":[\"Mi?narodny Universitet \\\"MITSO\\\"\"]}]"
Seeing the actual content without extra double-quotes and backslashes needed to show String as String-literal, it looks like some valid JSON is embedded in a String.
This may happen when the server side code double-encodes the data. You should better tell your server side engineer to fix the issue, but if it is difficult or would take long time, you can double-decode it.
Testing code:
import Foundation
let dataStr = "<225b7b5c 2276616c 75655c22 3a5c2249 6e746572 6e617469 6f6e616c 20556e69 76657273 69747920 5c5c5c22 4d495453 4f5c5c5c 225c222c 5c226964 5c223a5c 22613176 32343030 30303030 754f7250 4141555c 222c5c22 6164646c 4669656c 64735c22 3a5b5c22 4d693f6e 61726f64 6e792055 6e697665 72736974 6574205c 5c5c224d 4954534f 5c5c5c22 5c225d7d 5d22>".dropFirst().dropLast().replacingOccurrences(of: " ", with: "")
let byteArr = stride(from: 0, to: dataStr.count, by: 2).map{(index: Int)->UInt8 in
let start = dataStr.index(dataStr.startIndex, offsetBy: index)
let end = dataStr.index(start, offsetBy: 2)
return UInt8(dataStr[start..<end], radix: 16)!
}
let responseData = Data(bytes: byteArr)
print(responseData as NSData)
Check here, whether the print statement output is exactly the same as your sample response. (If you want to test the following code with your actual data than sample response, use just let responseData = result as! Data instead of above lines.)
So, you just need to use JSONSerialization twice:
block: do {
let firstDecoded = try JSONSerialization.jsonObject(with: responseData, options: .allowFragments) as! String
let firstDecodedData = firstDecoded.data(using: .utf8)!
let secondDecoded = try JSONSerialization.jsonObject(with: firstDecodedData)
//Code below is an example of using decoded result.
guard let resultArray = secondDecoded as? [[String: Any]] else {
print("result is not an Array of Dictionary")
break block
}
print(resultArray)
if
let addlFields = resultArray[0]["addlFields"] as? [String],
let firstAddl = addlFields.first
{
print(firstAddl)
}
} catch {
print(error)
}
Outputs: (Omitting some output for print(responseData as NSData).)
[["id": a1v24000000uOrPAAU, "value": International University "MITSO", "addlFields": <__NSSingleObjectArrayI 0x100e40c80>(
Mi?narodny Universitet "MITSO"
)
]]
Mi?narodny Universitet "MITSO"
(You may find some parts like <__NSSingleObjectArrayI 0x100e40c80> are strange, but it's just a problem of generating default description and you can access the elements as an Array.)
Anyway, please try and see what you can get with my code above.
#OOPer thank you for the solution. Appreciate you giving your time.
Solution worked as expected. Pasting code here which may help others.
Here is how I am doing -
func getData(text:String, callback:#escaping (_ result: Array<somedata>?,_ error:Error?) -> Void) {
let params = ["search":text]
getDataSomeAPI(url: "http:\\xyz.com\fdf", params: params) { (result, error) in
if error == nil {
do {
//Response is double encoded
if let firstDecoded = try JSONSerialization.jsonObject(with: result as! Data, options: .allowFragments) as? String
{
let firstDecodedData = firstDecoded.data(using: .utf8)!
if let secondDecoded = try JSONSerialization.jsonObject(with: firstDecodedData) as? NSArray {
var array = [somedata]()
for obj in secondDecoded {
Mapper<somedata>().map(JSONObject: obj).then { mappedObj in
array.append(mappedObj)
}
}
callback(array,nil)
}
}
}
catch {
//Handle unexpected data format
let error = NSError(domain: "",
code: 0,
userInfo: nil)
let sErr = Error(err: error)
callback(nil, sErr)
}
} else {
callback(nil, error)
}
}
}

JSON Parsing in Swift 3

Has anyone been able to find a way to parse through JSON files in Swift 3? I have been able to get the data to return but I am unsuccessful when it comes to breaking the data down into specific fields. I would post sample code but I've gone through so many different methods unsuccessfully and haven't saved any. The basic format I want to parse through is something like this. Thanks in advance.
{
"Language": {
"Field":[
{
"Number":"976",
"Name":"Test"
},
{
"Number":"977",
"Name":"Test"
}
]
}
}
Have you tried JSONSerialization.jsonObject(with:options:)?
var jsonString = "{" +
"\"Language\": {" +
"\"Field\":[" +
"{" +
"\"Number\":\"976\"," +
"\"Name\":\"Test\"" +
"}," +
"{" +
"\"Number\":\"977\"," +
"\"Name\":\"Test\"" +
"}" +
"]" +
"}" +
"}"
var data = jsonString.data(using: .utf8)!
let json = try? JSONSerialization.jsonObject(with: data)
Swift sometimes produces some very odd syntax.
if let number = json?["Language"]??["Field"]??[0]?["Number"] as? String {
print(number)
}
Everything in the JSON object hierarchy ends up getting wrapped as an optional (ie. AnyObject?). Array<T> subscript returns a non-optional T. For this JSON, which is wrapped in an optional, array subscript returns Optional<AnyObject>. However, Dictionary<K, V> subscript returns an Optional<V>. For this JSON, subscript returns the very odd looking
Optional<Optional<AnyObject>> (ie. AnyObject??).
json is an Optional<AnyObject>.
json?["Language"] returns an Optional<Optional<AnyObject>>.
json?["Language"]??["Field"] returns an Optional<Optional<AnyObject>>.
json?["Language"]??["Field"]??[0] returns an Optional<AnyObject>.
json?["Language"]??["Field"]??[0]?["Number"] returns an Optional<Optional<AnyObject>>.
json?["Language"]??["Field"]??[0]?["Number"] as? String returns an Optional<String>.
The Optional<String> is then used by the if let syntax to product a String.
Final note: iterating the field array looks like this.
for field in json?["Language"]??["Field"] as? [AnyObject] ?? [] {
if let number = field["Number"] as? String {
print(number)
}
}
Swift 4 Update
Swift 4 makes this all much easier to deal with. Again we will start with your test data (""" makes this so much nicer).
let data = """
{
"Language": {
"Field":[
{
"Number":"976",
"Name":"Test"
},
{
"Number":"977",
"Name":"Test"
}
]
}
}
""".data(using: .utf8)!
Next we can define classes around the objects used in your JSON.
struct Object: Decodable {
let language: Language
enum CodingKeys: String, CodingKey { case language="Language" }
}
struct Language: Decodable {
let fields: [Field]
enum CodingKeys: String, CodingKey { case fields="Field" }
}
struct Field: Decodable {
let number: String
let name: String
enum CodingKeys: String, CodingKey { case number="Number"; case name="Name" }
}
The CodingKeys enum is how struct properties are mapped to JSON object member strings. This mapping is done automagically by Decodable.
Parsing the JSON now is simple.
let object = try! JSONDecoder().decode(Object.self, from: data)
print(object.language.fields[0].name)
for field in object.language.fields {
print(field.number)
}
In Xcode 8 and Swift 3 id now imports as Any rather than AnyObject
This means that JSONSerialization.jsonObject(with: data) returns Any. So you have to cast the json data to a specific type like [String:Any]. Same applies to the next fields down the json.
var jsonString = "{" +
"\"Language\": {" +
"\"Field\":[" +
"{" +
"\"Number\":\"976\"," +
"\"Name\":\"Test1\"" +
"}," +
"{" +
"\"Number\":\"977\"," +
"\"Name\":\"Test2\"" +
"}" +
"]" +
"}" +
"}"
var data = jsonString.data(using: .utf8)!
if let parsedData = try? JSONSerialization.jsonObject(with: data) as! [String:Any] {
let language = parsedData["Language"] as! [String:Any]
print(language)
let field = language["Field"] as! [[String:Any]]
let name = field[0]["Name"]!
print(name) // ==> Test1
}
In practice you would probably want some specific field buried in the json. Lets assume it's the Name field of the first element of Field array. You can use a chain of unwraps like this to safely access the field:
var data = jsonString.data(using: .utf8)!
if let json = try? JSONSerialization.jsonObject(with: data) as? [String:Any],
let language = json?["Language"] as? [String:Any],
let field = language["Field"] as? [[String:Any]],
let name = field[0]["Name"] as? String, field.count > 0 {
print(name) // ==> Test1
} else {
print("bad json - do some recovery")
}
Also you may want to check Apple's Swift Blog Working with JSON in Swift
Shoving JSON into a string manually is a pita. Why don't you just put the JSON into a file and read that in?
Swift 3:
let bundle = Bundle(for: type(of: self))
if let theURL = bundle.url(forResource: "response", withExtension: "json") {
do {
let data = try Data(contentsOf: theURL)
if let parsedData = try? JSONSerialization.jsonObject(with: data) as! [String:Any] {
grok(parsedData)
}
} catch {
print(error)
}
}
override func viewDidLoad() {
super.viewDidLoad()
let url=URL(string:"http://api.androidhive.info/contacts/")
do {
let allContactsData = try Data(contentsOf: url!)
let allContacts = try JSONSerialization.jsonObject(with: allContactsData, options: JSONSerialization.ReadingOptions.allowFragments) as! [String : AnyObject]
if let arrJSON = allContacts["contacts"] {
for index in 0...arrJSON.count-1 {
let aObject = arrJSON[index] as! [String : AnyObject]
names.append(aObject["name"] as! String)
contacts.append(aObject["email"] as! String)
}
}
print(names)
print(contacts)
self.tableView.reloadData()
}
catch {
}
}
JSON Parsing in swift 4 using Decodable Protocol :
I create a mocky file using your json object :
http://www.mocky.io/v2/5a280c282f0000f92c0635e6
Here is the code to parse the JSON :
Model Creation :
import UIKit
struct Item : Decodable {
// Properties must be the same name as specified in JSON , else it will return nil
var Number : String
var Name : String
}
struct Language : Decodable {
var Field : [Item]
}
struct Result : Decodable {
var Language : Language
}
You can use optional in the model if you are uncertain that something might be missing in JSON file.
This is the parsing Logic :
class ViewController: UIViewController {
let url = "http://www.mocky.io/v2/5a280c282f0000f92c0635e6"
private func parseJSON() {
guard let url = URL(string: url) else { return }
let session = URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let data = data else { return }
guard let result = try? JSONDecoder().decode(Result.self, from: data) else { return }
print("\n\nResult : \(result)")
}
session.resume()
}
override func viewDidLoad() {
super.viewDidLoad()
parseJSON()
}
}
The Print Output :
Result : Result(Language: JSON_Parsing.Language(Field: [JSON_Parsing.Item(Number: "976", Name: "Test"), JSON_Parsing.Item(Number: "977", Name: "Test")]))
This the github Project link. You can check.
JSON Parsing using Swift 4 in Simple WAY
let url = URL(string: "http://mobileappdevelop.co/TIPIT/webservice/get_my_groups?user_id=5")
URLSession.shared.dataTask(with:url!, completionHandler: {(data, response, error) in
guard let data = data, error == nil else { return }
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String:Any]
print(json)
let posts = json["Field"] as? [[String: Any]] ?? []
print(posts)
} catch let error as NSError {
print(error)
}
}).resume()
}
Use SwiftJson library. I think its very easy way to parse.
let count: Int? = json["Field"].array?.count
if let ct = count {
for index in 0...ct-1{
let number = json ["Field"][index]["number"].string
let name = json ["Field"][index]["name"].string
....
like this .
dict = {
message = "Login successfully.";
status = 1;
"user_details" = (
{
dob = "1900-11-18";
email = "rizwan#gmail.com";
gender = male;
name = Rizwan;
nickname = Shaikh;
"profile_pic" = "1483434421.jpeg";
"social_id" = "<null>";
"user_id" = 2;
}
);
}
We can parse above json in Swift 3 as
var dict2 = dict as! [String : Any]
print(dict);
let demoStr = dict2["message"] as! String
print(demoStr)
let demoArray = dict2["user_details"] as! [Any]
let demoDict = demoArray[0] as! [String:Any]
print(demoDict["dob"]!)

Swift2 JSON Parsing with multiple dictionaries

I have successfully read the data from the following site: http://free.currencyconverterapi.com/api/v3/countries. I can see the values in the debug window. However, I am unable to iterate over the items. There are more than 200 items and I would like to iterate through them and print out their values (name, currency name, id, etc...)
The code to read the data:
func countryList() {
// Do any additional setup after loading the view.
let jsonUrl = "http://free.currencyconverterapi.com/api/v3/countries"
let session = NSURLSession.sharedSession()
let shotsUrl = NSURL(string: jsonUrl)
let task = session.dataTaskWithURL(shotsUrl!) {
(data, response, error) -> Void in
do {
let jsonData = try NSJSONSerialization.JSONObjectWithData(data!, options:NSJSONReadingOptions.MutableContainers ) as! NSDictionary
//let results: [String:[String:[String]]] = jsonData["results"]! as! [String : [String : [String]]]
let results = jsonData["results"]!
// iterate all items and print values
// how ???
} catch _ {
// Error
}
}
task.resume()
}
I have tried the following: let results : [String:[String:[String]]] = jsonData["results"]! however this does not work, and I would be surprised if it did :).
Any pointers?
using Xcode 7.1 and Swift 2
Result data returned with JSON (sample):
Country & Currency List{
"results":{
"GQ":{
"currencyId":"GQE",
"currencyName":"Central African CFA franc",
"name":"Equatorial Guinea",
"alpha3":"GNQ",
"id":"GQ"
},
"TD":{
"currencyId":"XAF",
"currencyName":"Central African CFA franc",
"name":"Chad",
"alpha3":"TCD",
"id":"TD"
}
.
.
.
The value of key results is a dictionary, it can be enumerated with a simple for .. in loop.
countrycode is the key, info the value.
Downcasting a dictionary to [String:AnyObject] includes all forms of nested objects.
This code prints out the country code and the name of each item
do {
let jsonData = try NSJSONSerialization.JSONObjectWithData(data!, options:NSJSONReadingOptions.MutableContainers ) as! [String:AnyObject]
let results = jsonData["results"] as! [String:AnyObject]
for (countryCode, info) in results {
print(countryCode, info["name"] as! String)
}
}
Be aware that there is no order because a dictionary is unordered by definition