Accessing Object Attributes from JSON, Swift3 - json

let url = URL(string: "http://192.168.30.243:5000/trippy/destination/info?id=4864cc0a-8")
let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error != nil {
print ("ERROR")
}
else {
if let content = data {
do {
//Array
let myJson = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
print(myJson)
if let information = myJson as? NSDictionary {
print (information.value(forKey: "EmergencyNumbers")!)
if let number = information.value(forKey: "EmergencyNumbers") as? NSArray {
//This is the part I am unsure about
if let description = number[0] as? AnyObject {
//I know do not know how to access the object's attribute values
}
}
}
}
catch {
}
}
}
}
task.resume()
}
I have used JSON to parse data from the web. I have utilized a dictionary to access the information and then an array to get the data from the certain key. Within this array are lie some objects. How do I access each of these objects' properties' values?
JSON Example:
{
Currency = testCurrency;
DestinationId = "4864cc0a-8";
DialCode = testDialCode;
DoesntUseMetricSystem = 0;
DrinkingAge = 16;
DriverLicense = 1;
EmergencyNumbers = (
{
Description = "Emergency Pizza Delivery";
Id = 1;
Number = 6969;
}
);
Id = 1;
IsNorthHemisphere = 1;
OfficialLanguage = {
Id = 1;
Name = testLanguage;
};
PowerGridVoltage = 226;
PowerSocket = dk;
Telecoms = nonern;
Tipping = 2;
WidelySpokenLanguages = (
{
Id = 2;
Name = testtLanguage;
}
);
WrongSideOfRoad = 0;
}

I see you are coming from Objective-C world, so first I'd recommend you give up using NSArray, NSDictionary etc. in favor of their Swift counterparts Array and Dictionary:
let task = URLSession.shared.dataTask(with: url!) { data, response, error in
...
let JSON = try? JSONSerialization.jsonObject(with: data!, options: [])
if let dictionary = JSON as? [String: Any],
let emergencyNumbers = dictionary["EmergencyNumbers"] as? [[String: Any]]
{
emergencyNumbers.forEach { numbers in
print(numbers["Description"] as? String)
print(numbers["Id"] as? Int)
print(numbers["Number"] as? Int)
}
}
}
By the way [String: Any] is just a syntactic sugar for Dictionary<String, Any>. Same applies to arrays as well: [[String: Any]] is for Array<Dictionary<String, Any>>.

As always, don't use NSArray / NSDictionary in Swift. You throw away the type information.
The root object is a dictionary ([String:Any]), the value for key EmergencyNumbers is an array ([[String:Any]]). Use a loop to iterate thru the array.
if let root = try JSONSerialization.jsonObject(with: content) as? [String:Any] {
print(myJson)
if let emergencyNumbers = root["EmergencyNumbers"] as? [[String:Any]] {
for emergencyNumber in emergencyNumbers {
let description = emergencyNumber["Description"] as? String
let id = emergencyNumber["Id"] as? Int
let number = emergencyNumber["Number"] as? Int
print("description", description ?? "n/a")
print("id", id ?? "n/a")
print("number", number ?? "n/a")
}
}
Some other bad habits:
.mutableContainers is completely meaningless in Swift. The hilarious thing is, everybody who passes the option .mutableContainers assigns the result to an immutable constant.
The unspecified JSON type in Swift 3+ is Any not AnyObject
valueForKey, a KVC method, is inappropriate for this purpose, use objectForKey or key subscription. With Swift native types don't use it at all.

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

Accessing JSON data with Swift

I have an array of JSON data from the following call:
guard let json = (try? JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers)) as? [Any] else {
print("Not containing JSON")
return
}
when I run print(json) I get the following in the output:
[{
"CREATED_BY" = "DOMAIN\\USER";
"CREATED_DATE" = "2016-11-28T08:43:59";
STATUS = U;
"WIDGET_NUMBER" = K11;
"UPDATED_BY" = "<null>";
"UPDATED_DATE" = "<null>";
}, {
"CREATED_BY" = "DOMAIN\\USER";
"CREATED_DATE" = "2016-05-09T08:46:23";
STATUS = U;
"WIDGET_NUMBER" = 89704;
"UPDATED_BY" = "<null>";
"UPDATED_DATE" = "<null>";
}]
I am trying to get all of the WIDGETNUMBER values in the array of JSON data. The json variable is a Any type and I have not been able to convert to a struct so far. Is there an easy way to get the elements from the JSON objects?
It looks like you have an array of dictionaries
for item in json {
if let item = item as? [String: Any], let widgetNo = item["WIDGET_NUMBER"] {
print(widgetNo)
}
}
Your content is array of Dictionary, so that you must convert each element Dictionary to Json
for dic in content {
do {
let jsonData = try JSONSerialization.data(withJSONObject: dic, options: .prettyPrinted)
print(jsonData)
} catch {
print(error.localizedDescription)
}
}
Or you can read value of WIDGET_NUMBER direct from Dictionary
for dic in content {
print(dic["WIDGET_NUMBER"] ?? "Not found")
}
Joakim's answer is spot on for getting the widget number. For your struct, be sure to add something like this as an initializer to map your object.
let widgetNumber: Int
let user: String
init?(json:[String:Any]) {
guard let widgetNumber = json["WIDGET_NUMBER"] as? Int,
let user = json["CREATED_BY"] as? String else { return nil }
self.widgetNumber = widgetNumber
self.user = user
}
If you just want an array of widget numbers you could use the reduce function which iterates the dictionaries in the array and extracts the widget numbers:
Using your data I put this in a storyboard:
let json = try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves) as! [[String: Any]]
let widgetNumbers = json?.reduce(into: [String]()){ (accum, dict) in
guard let widget = dict["WIDGET_NUMBER"] as? String else { return }
accum.append(widget)
}
widgetNumbers // -> ["K11", "89704"]

Trouble getting data from TheMovieDB API with Swift JSON

I am brand new to using JSON and wanted to get started with a simple app to provide a movie overview when you type in a title. My below code returns everything in one big string. How do I get just one piece of information like the overview or year?
With my below attempt, print(obj["overview"] as Any)) prints "nil" and print(obj) looks like this:
{
page = 1;
results = (
{
adult = 0;
"backdrop_path" = "/A0aGxrCGRBuCrDltGYiKGeAUect.jpg";
"genre_ids" = (
53,
80
);
id = 680;
"original_language" = en;
"original_title" = "Pulp Fiction";
overview = "A burger-loving hit man, his philosophical partner, a drug-addled gangster's moll and a washed-up boxer converge in this sprawling, comedic crime caper. Their adventures unfurl in three stories that ingeniously trip back and forth in time.";
Current Code:
let query = "Pulp+Fiction"
let urlString = "https://api.themoviedb.org/3/search/movie?api_key={MYAPIKEY}&query=\(query)"
let url = URL(string: urlString)
URLSession.shared.dataTask(with:url!) { (data, response, error) in
if error != nil {
print(error as Any)
} else {
do {
let parsedData = try JSONSerialization.jsonObject(with: data!) as Any
if let obj = parsedData as? NSDictionary {
print(obj["overview"] as Any)
print(obj)
}
} catch {
print("error")
} }
}.resume()
}
// write this extension anywhere in your any swift file
extension String{
func toDictionary() -> NSDictionary {
let blankDict : NSDictionary = [:]
if let data = self.data(using: .utf8) {
do {
return try JSONSerialization.jsonObject(with: data, options: []) as! NSDictionary
} catch {
print(error.localizedDescription)
}
}
return blankDict
}
}
//now in your code modify as
if data != nil {
let responseString = String(data: data!, encoding: .utf8)!
if(responseString != "")
{
//convert response string into dictionary using extended method
let responseValues = responseString.toDictionary()
//access value using keyPath using
let value = responseValues.value(forKeyPath: "key.key2")
//where key2 is the target key which is inside the value of key
}
}
First of all JSON results are never Any. As already mentioned in the comments the root object is a dictionary
if let parsedData = try JSONSerialization.jsonObject(with: data!) as? [String:Any],
The key overview is in array for key results
let results = parsedData["results"] as? [[String:Any]] {
You have to iterate over the array to get the values for key overview
for result in results {
print(result["overview"] as? String ?? "no value for key overview")
}
}
It's highly recommended to use the Codable protocol and custom structs in Swift 4.

How to get the multiple data inside the json curly braces? Swift

How to get the multiple data inside the json curly braces in swift3?
Can i use this code to get multiple data? (get "crew_id","crew_name","crew_email")
if let crew = user!["crew"] as? [String:Any], let crewName = crew["crew_name"] as? String {
print(crewName)
JSON
crew ={
"crew_avatar" = "http://ec2-52-221-231-3.ap-southeast-1.compute.amazonaws.com/gv/images/profile_image/Pang_Kang_Ming_916210_0e9.jpg";
"crew_contact" = 0123456789;
"crew_email" = "pang#xover.com.my";
"crew_gender" = Male;
"crew_id" = PP000001;
"crew_name" = "Pang Kang Ming";
"crew_preferred_name" = PKM;
"crew_qrcode" = "images/qrcode/qrcode_085960293a5378a64bec6ebfa3c89bb7.png";
};
message = "Login Sucessfully";
result = success;
Yes you can, just add the values you want to unwrap as below, just be aware that if one of the optional binding does not unwrap, even if others unwrap if statement will not be executed, consider separating the if statements.
Depends on all being returned in the json.
if let crew = user!["crew"] as? [String:Any],
let crewName = crew["crew_name"] as? String,
let crewId = crew["crew_id"] as? String {
print(crewName)
print(crewId)
}
Recommended way, even if some values are not present in the json response, you will be able to get the other values.
if let crew = user!["crew"] as? [String:Any] {
if let crewName = crew["crew_name"] as? String {
print(crewName)
}
if let crewId = crew["crew_id"] as? String {
print(crewId)
}
}
if let file = Bundle.main.url(forResource: "yourJsonFileName", withExtension: "json") {
let data = try Data(contentsOf: file)
let json = try JSONSerialization.jsonObject(with: data, options: [])
let jsonData = json as! [[String:Any]]
DispatchQueue.main.async {
let projectName = jsonData.flatMap { $0["crew_avatar"] as? String }
self.crewAvatarArray = projectName
print(self.crewAvatarArray)
let subTitle = jsonData.flatMap { $0["crew_contact"] as? String }
self.crewContactArray = subTitle
let startDate = jsonData.flatMap { $0["crew_email"] as? String }
self.crewEmailArray = startDate
}
}
Try this code

Grab data from JSON file doesn't work

I try to grab data from JSON (http://www.openligadb.de/api/getmatchdata/bl1/2014/15). I want to get every single game with the goals, location, team ...
I tried this but it won't work.
let url = "http://www.openligadb.de/api/getmatchdata/bl1/2014/15"
//parse url
if let JSONData = NSData(contentsOfURL: NSURL(string: url)!) {
if let json = (try? NSJSONSerialization.JSONObjectWithData(JSONData, options: [])) as? NSDictionary {
//handle json
}
}
It doesn't steps in the 2nd if-statement (if let json = (try?...).
I hope you could help me.
Edit get data of dictionaries:
//Data Team1
if let team1 = object["Team1"] as? NSDictionary {
if let name = team1["TeamName"] as? String {
print("Name Team1: \(name)")
}
if let logo = team1["TeamIconUrl"] as? String {
print("Logo Team1: \(logo)")
}
// Etc.
}
What you need to do is to understand your JSON structure: you have an array first, not a dictionary.
This array has dictionaries, each of them holding an array of dictionaries.
It may sound complex but it's actually simple, you just follow the structure of your JSON and decode the values with the correct type.
In JSON, an array starts with [ and a dictionary starts with { (also, be careful not to confuse this JSON syntax with Swift's arrays and dictionaries one).
Your code could be something like this, for example:
do {
let url = "http://www.openligadb.de/api/getmatchdata/bl1/2014/15"
if let url = NSURL(string: url),
JSONData = NSData(contentsOfURL: url),
jsonArray = try NSJSONSerialization.JSONObjectWithData(JSONData, options: []) as? NSArray {
for object in jsonArray {
if let goalsArray = object["Goals"] as? NSArray {
// Each "goal" is a dictionary
for goal in goalsArray {
print(goal)
if let name = goal["GoalGetterName"] as? String {
print("Name: \(name)")
}
if let ID = goal["GoalID"] as? Int {
print("ID: \(ID)")
}
// Etc.
}
}
}
}
} catch {
print(error)
}
UPDATE: you're almost there! But "Team1" is a dictionary, not an array. :)
Here's the solution:
do {
let url = "http://www.openligadb.de/api/getmatchdata/bl1/2014/15"
if let url = NSURL(string: url),
JSONData = NSData(contentsOfURL: url),
jsonArray = try NSJSONSerialization.JSONObjectWithData(JSONData, options: []) as? NSArray {
for object in jsonArray {
if let team1 = object["Team1"] as? NSDictionary {
if let name = team1["TeamName"] as? String {
print("Name Team1: \(name)")
}
if let logo = team1["TeamIconUrl"] as? String {
print("Logo Team1: \(logo)")
}
}
}
}
} catch {
print(error)
}